<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
	<id>https://wiki.gis-lab.info/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Oldbay</id>
	<title>GIS-Lab - Вклад [ru]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.gis-lab.info/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Oldbay"/>
	<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/w/%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/Oldbay"/>
	<updated>2026-07-12T18:35:11Z</updated>
	<subtitle>Вклад</subtitle>
	<generator>MediaWiki 1.39.6</generator>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26179</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26179"/>
		<updated>2018-06-01T12:22:25Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* Трансформация. */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif (img 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 1 - data/multi.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif (img 2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 2 - result/calc.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|600px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area. ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif (img 3.1 ,img 3.2)&lt;br /&gt;
&lt;br /&gt;
img 3.1 - отображение области на исходном растре&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords_screenshot.png|500px]]&lt;br /&gt;
&lt;br /&gt;
img 3.2 - result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file. ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif (img 4.1, img 4.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.1 - геометрия из shp файла на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp_screenshot.png|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.2 - result/cut_shp.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry. ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif (img 5.1, img 5.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.1 - отображение геометрии из postgis на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt_screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.2 - result/cut_wkt.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Трансформация.==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность всего массива, или только его части.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210)-img 6.1, (125,105)-img 6.2, (300,300)-img 6.3. Последний массив сохранится в растр result/resize.tif (img 6.3).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (253x210)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_253_210.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (125x105)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_125_105.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (300x300)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_300_300.png|500px]]&lt;br /&gt;
&lt;br /&gt;
==Мультирастры.==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif (img 7).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 7 - result/multi_rebands.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi_rebands.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif (img 8).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 8 - result/multi_opencv.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi_opencv.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|600px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Ремонт&amp;quot; георастров.==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y. Примером утилиты с такой странной процедурной генерации является gdal_grid([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]).&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Послесловие.==&lt;br /&gt;
&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26178</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26178"/>
		<updated>2018-06-01T12:20:17Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* Растровый калькулятор. */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif (img 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 1 - data/multi.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif (img 2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 2 - result/calc.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|600px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area. ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif (img 3.1 ,img 3.2)&lt;br /&gt;
&lt;br /&gt;
img 3.1 - отображение области на исходном растре&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords_screenshot.png|500px]]&lt;br /&gt;
&lt;br /&gt;
img 3.2 - result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file. ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif (img 4.1, img 4.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.1 - геометрия из shp файла на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp_screenshot.png|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.2 - result/cut_shp.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry. ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif (img 5.1, img 5.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.1 - отображение геометрии из postgis на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt_screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.2 - result/cut_wkt.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Трансформация.==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210)-img 6.1, (125,105)-img 6.2, (300,300)-img 6.3. Последний массив сохранится в растр result/resize.tif (img 6.3).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (253x210)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_253_210.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (125x105)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_125_105.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (300x300)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_300_300.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Мультирастры.==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif (img 7).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 7 - result/multi_rebands.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi_rebands.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif (img 8).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 8 - result/multi_opencv.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi_opencv.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|600px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Ремонт&amp;quot; георастров.==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y. Примером утилиты с такой странной процедурной генерации является gdal_grid([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]).&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Послесловие.==&lt;br /&gt;
&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26177</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26177"/>
		<updated>2018-06-01T12:19:28Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif (img 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 1 - data/multi.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif (img 2).&lt;br /&gt;
&lt;br /&gt;
img 2 - result/calc.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|600px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area. ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif (img 3.1 ,img 3.2)&lt;br /&gt;
&lt;br /&gt;
img 3.1 - отображение области на исходном растре&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords_screenshot.png|500px]]&lt;br /&gt;
&lt;br /&gt;
img 3.2 - result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file. ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif (img 4.1, img 4.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.1 - геометрия из shp файла на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp_screenshot.png|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.2 - result/cut_shp.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry. ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif (img 5.1, img 5.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.1 - отображение геометрии из postgis на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt_screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.2 - result/cut_wkt.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Трансформация.==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210)-img 6.1, (125,105)-img 6.2, (300,300)-img 6.3. Последний массив сохранится в растр result/resize.tif (img 6.3).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (253x210)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_253_210.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (125x105)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_125_105.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (300x300)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_300_300.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Мультирастры.==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif (img 7).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 7 - result/multi_rebands.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi_rebands.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif (img 8).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 8 - result/multi_opencv.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi_opencv.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|600px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Ремонт&amp;quot; георастров.==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y. Примером утилиты с такой странной процедурной генерации является gdal_grid([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]).&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Послесловие.==&lt;br /&gt;
&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26176</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26176"/>
		<updated>2018-06-01T12:17:45Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* Знакомство с raster_tools */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif (img 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 1 - data/multi.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif (img 2).&lt;br /&gt;
&lt;br /&gt;
img 2 - result/calc.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|600px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area. ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif (img 3.1 ,img 3.2)&lt;br /&gt;
&lt;br /&gt;
img 3.1 - отображение области на исходном растре&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords_screenshot.png|500px]]&lt;br /&gt;
&lt;br /&gt;
img 3.2 - result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file. ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif (img 4.1, img 4.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.1 - геометрия из shp файла на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp_screenshot.png|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.2 - result/cut_shp.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry. ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif (img 5.1, img 5.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.1 - отображение геометрии из postgis на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt_screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.2 - result/cut_wkt.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Трансформация.==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210)-img 6.1, (125,105)-img 6.2, (300,300)-img 6.3. Последний массив сохранится в растр result/resize.tif (img 6.3).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (253x210)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_253_210.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (125x105)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_125_105.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (300x300)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_300_300.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Мультирастры.==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif (img 7).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 7 - result/multi_rebands.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi_rebands.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif (img 8).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 8 - result/multi_opencv.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi_opencv.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|600px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Ремонт&amp;quot; георастров.==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y. Примером утилиты с такой странной процедурной генерации является gdal_grid([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]).&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Послесловие.==&lt;br /&gt;
&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26175</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26175"/>
		<updated>2018-06-01T12:17:26Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif (img 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 1 - data/multi.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif (img 2).&lt;br /&gt;
&lt;br /&gt;
img 2 - result/calc.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|600px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area. ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif (img 3.1 ,img 3.2)&lt;br /&gt;
&lt;br /&gt;
img 3.1 - отображение области на исходном растре&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords_screenshot.png|500px]]&lt;br /&gt;
&lt;br /&gt;
img 3.2 - result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file. ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif (img 4.1, img 4.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.1 - геометрия из shp файла на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp_screenshot.png|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.2 - result/cut_shp.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry. ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif (img 5.1, img 5.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.1 - отображение геометрии из postgis на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt_screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.2 - result/cut_wkt.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Трансформация.==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210)-img 6.1, (125,105)-img 6.2, (300,300)-img 6.3. Последний массив сохранится в растр result/resize.tif (img 6.3).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (253x210)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_253_210.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (125x105)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_125_105.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (300x300)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_300_300.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Мультирастры.==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif (img 7).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 7 - result/multi_rebands.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi_rebands.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif (img 8).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 8 - result/multi_opencv.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi_opencv.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|600px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Ремонт&amp;quot; георастров.==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y. Примером утилиты с такой странной процедурной генерации является gdal_grid([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]).&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Послесловие.==&lt;br /&gt;
&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26174</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26174"/>
		<updated>2018-06-01T12:13:27Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* Обработка муьтирастров в opencv. */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif (img 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 1 - data/multi.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif (img 2).&lt;br /&gt;
&lt;br /&gt;
img 2 - result/calc.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|600px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif (img 3.1 ,img 3.2)&lt;br /&gt;
&lt;br /&gt;
img 3.1 - отображение области на исходном растре&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords_screenshot.png|500px]]&lt;br /&gt;
&lt;br /&gt;
img 3.2 - result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords.png|200px]]&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif (img 4.1, img 4.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.1 - геометрия из shp файла на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp_screenshot.png|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.2 - result/cut_shp.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif (img 5.1, img 5.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.1 - отображение геометрии из postgis на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt_screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.2 - result/cut_wkt.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt.png|200px]]&lt;br /&gt;
&lt;br /&gt;
==Трансформация==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210)-img 6.1, (125,105)-img 6.2, (300,300)-img 6.3. Последний массив сохранится в растр result/resize.tif (img 6.3).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (253x210)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_253_210.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (125x105)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_125_105.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (300x300)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_300_300.png|500px]]&lt;br /&gt;
&lt;br /&gt;
==Мультирастры==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif (img 7).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 7 - result/multi_rebands.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi_rebands.png|500px]]&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif (img 8).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 8 - result/multi_opencv.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi_opencv.png|500px]]&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|600px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Ремонт&amp;quot; георастров==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y. Примером утилиты с такой странной процедурной генерации является gdal_grid([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]).&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y.&lt;br /&gt;
&lt;br /&gt;
==Послесловие==&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Multi_opencv.png&amp;diff=26173</id>
		<title>Файл:Multi opencv.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Multi_opencv.png&amp;diff=26173"/>
		<updated>2018-06-01T12:12:54Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: img 8 - result/multi_opencv.tif&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;img 8 - result/multi_opencv.tif&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26172</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26172"/>
		<updated>2018-06-01T12:07:28Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* Изменение последовательности каналов. */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif (img 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 1 - data/multi.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif (img 2).&lt;br /&gt;
&lt;br /&gt;
img 2 - result/calc.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|600px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif (img 3.1 ,img 3.2)&lt;br /&gt;
&lt;br /&gt;
img 3.1 - отображение области на исходном растре&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords_screenshot.png|500px]]&lt;br /&gt;
&lt;br /&gt;
img 3.2 - result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords.png|200px]]&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif (img 4.1, img 4.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.1 - геометрия из shp файла на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp_screenshot.png|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.2 - result/cut_shp.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif (img 5.1, img 5.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.1 - отображение геометрии из postgis на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt_screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.2 - result/cut_wkt.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt.png|200px]]&lt;br /&gt;
&lt;br /&gt;
==Трансформация==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210)-img 6.1, (125,105)-img 6.2, (300,300)-img 6.3. Последний массив сохранится в растр result/resize.tif (img 6.3).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (253x210)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_253_210.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (125x105)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_125_105.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (300x300)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_300_300.png|500px]]&lt;br /&gt;
&lt;br /&gt;
==Мультирастры==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif (img 7).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 7 - result/multi_rebands.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi_rebands.png|500px]]&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|600px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Ремонт&amp;quot; георастров==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y. Примером утилиты с такой странной процедурной генерации является gdal_grid([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]).&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y.&lt;br /&gt;
&lt;br /&gt;
==Послесловие==&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Multi_rebands.png&amp;diff=26171</id>
		<title>Файл:Multi rebands.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Multi_rebands.png&amp;diff=26171"/>
		<updated>2018-06-01T12:06:49Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: img 7 - result/multi_rebands.tif&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;img 7 - result/multi_rebands.tif&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26170</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26170"/>
		<updated>2018-06-01T11:55:59Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* Трансформация */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif (img 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 1 - data/multi.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif (img 2).&lt;br /&gt;
&lt;br /&gt;
img 2 - result/calc.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|600px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif (img 3.1 ,img 3.2)&lt;br /&gt;
&lt;br /&gt;
img 3.1 - отображение области на исходном растре&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords_screenshot.png|500px]]&lt;br /&gt;
&lt;br /&gt;
img 3.2 - result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords.png|200px]]&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif (img 4.1, img 4.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.1 - геометрия из shp файла на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp_screenshot.png|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.2 - result/cut_shp.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif (img 5.1, img 5.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.1 - отображение геометрии из postgis на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt_screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.2 - result/cut_wkt.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt.png|200px]]&lt;br /&gt;
&lt;br /&gt;
==Трансформация==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210)-img 6.1, (125,105)-img 6.2, (300,300)-img 6.3. Последний массив сохранится в растр result/resize.tif (img 6.3).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (253x210)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_253_210.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (125x105)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_125_105.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 6.1 - разрешение (300x300)&lt;br /&gt;
&lt;br /&gt;
[[Файл:Resize_300_300.png|500px]]&lt;br /&gt;
&lt;br /&gt;
==Мультирастры==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|600px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Ремонт&amp;quot; георастров==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y. Примером утилиты с такой странной процедурной генерации является gdal_grid([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]).&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y.&lt;br /&gt;
&lt;br /&gt;
==Послесловие==&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Resize_300_300.png&amp;diff=26169</id>
		<title>Файл:Resize 300 300.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Resize_300_300.png&amp;diff=26169"/>
		<updated>2018-06-01T11:52:42Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: img 6.1 - разрешение (300,300)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;img 6.1 - разрешение (300,300)&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Resize_125_105.png&amp;diff=26168</id>
		<title>Файл:Resize 125 105.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Resize_125_105.png&amp;diff=26168"/>
		<updated>2018-06-01T11:51:55Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: img 6.1 - разрешение (125,105)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;img 6.1 - разрешение (125,105)&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Resize_253_210.png&amp;diff=26167</id>
		<title>Файл:Resize 253 210.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Resize_253_210.png&amp;diff=26167"/>
		<updated>2018-06-01T11:51:24Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: img 6.1 - разрешение (253,210)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;img 6.1 - разрешение (253,210)&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26166</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26166"/>
		<updated>2018-06-01T11:37:17Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* Метод cut_shp_file */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif (img 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 1 - data/multi.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif (img 2).&lt;br /&gt;
&lt;br /&gt;
img 2 - result/calc.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|600px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif (img 3.1 ,img 3.2)&lt;br /&gt;
&lt;br /&gt;
img 3.1 - отображение области на исходном растре&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords_screenshot.png|500px]]&lt;br /&gt;
&lt;br /&gt;
img 3.2 - result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords.png|200px]]&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif (img 4.1, img 4.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.1 - геометрия из shp файла на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp_screenshot.png|300px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 4.2 - result/cut_shp.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_shp.png|200px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif (img 5.1, img 5.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.1 - отображение геометрии из postgis на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt_screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.2 - result/cut_wkt.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt.png|200px]]&lt;br /&gt;
&lt;br /&gt;
==Трансформация==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210), (125,105), (300,300). Последний массив сохранится в растр result/resize.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Мультирастры==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|600px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Ремонт&amp;quot; георастров==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y. Примером утилиты с такой странной процедурной генерации является gdal_grid([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]).&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y.&lt;br /&gt;
&lt;br /&gt;
==Послесловие==&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Cut_shp.png&amp;diff=26165</id>
		<title>Файл:Cut shp.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Cut_shp.png&amp;diff=26165"/>
		<updated>2018-06-01T11:36:16Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: img 4.2 - result/cut_shp.tif&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;img 4.2 - result/cut_shp.tif&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Cut_shp_screenshot.png&amp;diff=26164</id>
		<title>Файл:Cut shp screenshot.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Cut_shp_screenshot.png&amp;diff=26164"/>
		<updated>2018-06-01T11:35:22Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: img 4.1 - геометрия из shp файла на фоне исходного растра&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;img 4.1 - геометрия из shp файла на фоне исходного растра&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26163</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26163"/>
		<updated>2018-06-01T11:30:10Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* Метод cut_ogr_geometry */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif (img 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 1 - data/multi.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif (img 2).&lt;br /&gt;
&lt;br /&gt;
img 2 - result/calc.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|600px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif (img 3.1 ,img 3.2)&lt;br /&gt;
&lt;br /&gt;
img 3.1 - отображение области на исходном растре&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords_screenshot.png|500px]]&lt;br /&gt;
&lt;br /&gt;
img 3.2 - result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords.png|200px]]&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif (img 5.1, img 5.2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.1 - отображение геометрии из postgis на фоне исходного растра&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt_screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 5.2 - result/cut_wkt.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_wkt.png|200px]]&lt;br /&gt;
&lt;br /&gt;
==Трансформация==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210), (125,105), (300,300). Последний массив сохранится в растр result/resize.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Мультирастры==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|600px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Ремонт&amp;quot; георастров==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y. Примером утилиты с такой странной процедурной генерации является gdal_grid([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]).&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y.&lt;br /&gt;
&lt;br /&gt;
==Послесловие==&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Cut_wkt.png&amp;diff=26162</id>
		<title>Файл:Cut wkt.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Cut_wkt.png&amp;diff=26162"/>
		<updated>2018-06-01T11:27:49Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: img 5.2 - result/cut_wkt.tif&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;img 5.2 - result/cut_wkt.tif&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Cut_wkt_screenshot.png&amp;diff=26161</id>
		<title>Файл:Cut wkt screenshot.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Cut_wkt_screenshot.png&amp;diff=26161"/>
		<updated>2018-06-01T11:25:49Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: img 5.1 - отображение геометрии из postgis на фоне исходного растра&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;img 5.1 - отображение геометрии из postgis на фоне исходного растра&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26160</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26160"/>
		<updated>2018-06-01T10:25:01Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* Работа с точками. */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif (img 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 1 - data/multi.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif (img 2).&lt;br /&gt;
&lt;br /&gt;
img 2 - result/calc.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|600px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif (img 3.1 ,img 3.2)&lt;br /&gt;
&lt;br /&gt;
img 3.1 - отображение области на исходном растре&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords_screenshot.png|500px]]&lt;br /&gt;
&lt;br /&gt;
img 3.2 - result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords.png|200px]]&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
==Трансформация==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210), (125,105), (300,300). Последний массив сохранится в растр result/resize.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Мультирастры==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|600px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Ремонт&amp;quot; георастров==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y. Примером утилиты с такой странной процедурной генерации является gdal_grid([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]).&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y.&lt;br /&gt;
&lt;br /&gt;
==Послесловие==&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26159</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26159"/>
		<updated>2018-06-01T10:24:27Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* Растровый калькулятор. */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif (img 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 1 - data/multi.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif (img 2).&lt;br /&gt;
&lt;br /&gt;
img 2 - result/calc.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|600px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|600px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif (img 3.1 ,img 3.2)&lt;br /&gt;
&lt;br /&gt;
img 3.1 - отображение области на исходном растре&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords_screenshot.png|500px]]&lt;br /&gt;
&lt;br /&gt;
img 3.2 - result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords.png|200px]]&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
==Трансформация==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210), (125,105), (300,300). Последний массив сохранится в растр result/resize.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Мультирастры==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|800px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|800px]]&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Ремонт&amp;quot; георастров==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y. Примером утилиты с такой странной процедурной генерации является gdal_grid([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]).&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y.&lt;br /&gt;
&lt;br /&gt;
==Послесловие==&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26158</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26158"/>
		<updated>2018-06-01T10:21:43Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* Метод cut_area */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif (img 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 1 - data/multi.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif (img 2).&lt;br /&gt;
&lt;br /&gt;
img 2 - result/calc.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|800px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|800px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif (img 3.1 ,img 3.2)&lt;br /&gt;
&lt;br /&gt;
img 3.1 - отображение области на исходном растре&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords_screenshot.png|500px]]&lt;br /&gt;
&lt;br /&gt;
img 3.2 - result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Cut_coords.png|200px]]&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
==Трансформация==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210), (125,105), (300,300). Последний массив сохранится в растр result/resize.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Мультирастры==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|800px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|800px]]&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Ремонт&amp;quot; георастров==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y. Примером утилиты с такой странной процедурной генерации является gdal_grid([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]).&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y.&lt;br /&gt;
&lt;br /&gt;
==Послесловие==&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Cut_coords.png&amp;diff=26157</id>
		<title>Файл:Cut coords.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Cut_coords.png&amp;diff=26157"/>
		<updated>2018-06-01T10:20:31Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: img 3.2 - result/cut_coords.tif&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;img 3.2 - result/cut_coords.tif&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Cut_coords_screenshot.png&amp;diff=26156</id>
		<title>Файл:Cut coords screenshot.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Cut_coords_screenshot.png&amp;diff=26156"/>
		<updated>2018-06-01T10:18:00Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: img 3.1 - отображение области на исходном растре&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;img 3.1 - отображение области на исходном растре&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26155</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26155"/>
		<updated>2018-06-01T10:10:46Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* Растровый калькулятор. */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif (img 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
img 1 - data/multi.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Multi.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif (img 2).&lt;br /&gt;
&lt;br /&gt;
img 2 - result/calc.tif&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc.png|500px]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|800px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|800px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
==Трансформация==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210), (125,105), (300,300). Последний массив сохранится в растр result/resize.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Мультирастры==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|800px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|800px]]&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Ремонт&amp;quot; георастров==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y. Примером утилиты с такой странной процедурной генерации является gdal_grid([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]).&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y.&lt;br /&gt;
&lt;br /&gt;
==Послесловие==&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Calc.png&amp;diff=26154</id>
		<title>Файл:Calc.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Calc.png&amp;diff=26154"/>
		<updated>2018-06-01T10:08:24Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: img 2 - calc.tif&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;img 2 - calc.tif&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Calc.jpg&amp;diff=26153</id>
		<title>Файл:Calc.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Calc.jpg&amp;diff=26153"/>
		<updated>2018-06-01T09:55:07Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: img 2 - calc.tif&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;img 2 - calc.tif&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Multi.png&amp;diff=26152</id>
		<title>Файл:Multi.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Multi.png&amp;diff=26152"/>
		<updated>2018-06-01T09:48:03Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: исходный мультирастр&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;исходный мультирастр&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Multi.jpg&amp;diff=26151</id>
		<title>Файл:Multi.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Multi.jpg&amp;diff=26151"/>
		<updated>2018-06-01T09:37:08Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: исходный мультирастр&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;исходный мультирастр&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26150</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26150"/>
		<updated>2018-06-01T08:51:39Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* Знакомство с raster_tools */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif.&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|800px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|800px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
==Трансформация==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210), (125,105), (300,300). Последний массив сохранится в растр result/resize.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Мультирастры==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|800px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|800px]]&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Ремонт&amp;quot; георастров==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y. Примером утилиты с такой странной процедурной генерации является gdal_grid([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]).&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y.&lt;br /&gt;
&lt;br /&gt;
==Послесловие==&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26149</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26149"/>
		<updated>2018-06-01T08:37:12Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* Ремонт георастров */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif.&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|800px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|800px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
==Трансформация==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210), (125,105), (300,300). Последний массив сохранится в растр result/resize.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Мультирастры==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|800px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|800px]]&lt;br /&gt;
&lt;br /&gt;
==&amp;quot;Ремонт&amp;quot; георастров==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y. Примером утилиты с такой странной процедурной генерации является gdal_grid([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]).&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y.&lt;br /&gt;
&lt;br /&gt;
==Послесловие==&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26148</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26148"/>
		<updated>2018-06-01T08:35:42Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* Ремонт георастров */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif.&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|800px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|800px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
==Трансформация==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210), (125,105), (300,300). Последний массив сохранится в растр result/resize.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Мультирастры==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|800px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|800px]]&lt;br /&gt;
&lt;br /&gt;
==Ремонт георастров==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y. Примером утилиты с такой странной процедурной генерации является gdal_grid([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]).&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y.&lt;br /&gt;
&lt;br /&gt;
==Послесловие==&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26147</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26147"/>
		<updated>2018-06-01T08:27:01Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif.&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|800px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|800px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
==Трансформация==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210), (125,105), (300,300). Последний массив сохранится в растр result/resize.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Мультирастры==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
[[Файл:Point_data_load_array_mprof.png|800px]]&lt;br /&gt;
[[Файл:Point_data_dont_load_array_mprof.png|800px]]&lt;br /&gt;
&lt;br /&gt;
==Ремонт георастров==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y ([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]). Примером утилиты с такой странной процедурной генерации является gdal_grid.&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y. &lt;br /&gt;
&lt;br /&gt;
==Послесловие==&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Point_data_dont_load_array_mprof.png&amp;diff=26146</id>
		<title>Файл:Point data dont load array mprof.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Point_data_dont_load_array_mprof.png&amp;diff=26146"/>
		<updated>2018-06-01T08:25:55Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: график потребления памяти скриптом point_data_dont_load_array.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;график потребления памяти скриптом point_data_dont_load_array.py&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Point_data_load_array_mprof.png&amp;diff=26145</id>
		<title>Файл:Point data load array mprof.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Point_data_load_array_mprof.png&amp;diff=26145"/>
		<updated>2018-06-01T08:22:28Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: график потребления памяти скриптом point_data_load_array.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;график потребления памяти скриптом point_data_load_array.py&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26144</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26144"/>
		<updated>2018-06-01T08:11:53Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* Растровый калькулятор. */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif.&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
[[Файл:Calc_mprof.png|800px]]&lt;br /&gt;
[[Файл:Calc_iter_mprof.png|800px]]&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод выигрывает в потреблении памяти, но теряет в скорости расчётов. На текущем примере потери скорости не очень существенны  - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
==Трансформация==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210), (125,105), (300,300). Последний массив сохранится в растр result/resize.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Мультирастры==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
point_data_load_array.py&lt;br /&gt;
&lt;br /&gt;
img: logs/point_data_load_array_mprof.png&lt;br /&gt;
&lt;br /&gt;
point_data_dont_load_array.py&lt;br /&gt;
&lt;br /&gt;
img: logs/point_data_dont_load_array_mprof.png&lt;br /&gt;
&lt;br /&gt;
==Ремонт георастров==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y ([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]). Примером утилиты с такой странной процедурной генерации является gdal_grid.&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y. &lt;br /&gt;
&lt;br /&gt;
==Послесловие==&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Calc_iter_mprof.png&amp;diff=26143</id>
		<title>Файл:Calc iter mprof.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Calc_iter_mprof.png&amp;diff=26143"/>
		<updated>2018-06-01T08:06:35Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: график потребления памяти скриптом calc_iter.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;график потребления памяти скриптом calc_iter.py&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Calc_mprof.png&amp;diff=26142</id>
		<title>Файл:Calc mprof.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%A4%D0%B0%D0%B9%D0%BB:Calc_mprof.png&amp;diff=26142"/>
		<updated>2018-06-01T07:57:39Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: графики потребления памяти скрипта calc.py&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;графики потребления памяти скрипта calc.py&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26141</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26141"/>
		<updated>2018-05-31T15:17:55Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif.&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
calc.py&lt;br /&gt;
&lt;br /&gt;
img: logs/calc_mprof.png&lt;br /&gt;
&lt;br /&gt;
calc_iter.py&lt;br /&gt;
&lt;br /&gt;
img:logs/calc_iter_mprof.png&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод в несколько раз выигрывает в потреблении памяти, но теряет в скорости расчётов. Потери скорости не очень существенны на текущем примере - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
==Трансформация==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210), (125,105), (300,300). Последний массив сохранится в растр result/resize.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Мультирастры==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
point_data_load_array.py&lt;br /&gt;
&lt;br /&gt;
img: logs/point_data_load_array_mprof.png&lt;br /&gt;
&lt;br /&gt;
point_data_dont_load_array.py&lt;br /&gt;
&lt;br /&gt;
img: logs/point_data_dont_load_array_mprof.png&lt;br /&gt;
&lt;br /&gt;
==Ремонт георастров==&lt;br /&gt;
&lt;br /&gt;
Иногда процедурная генерация георастров некоторыми утилитами порождает «мутантов». При их отображении в gis программах проблема не заметна - так как геоданные будут правильно спозицианированны. Но при выгрузке из такого георастра numpy массива - оказывается что он зеркально отображён относительно оси x или y ([https://gis-lab.info/forum/viewtopic.php?f=30&amp;amp;t=20283 сообщение о проблеме на форуме]). Примером утилиты с такой странной процедурной генерации является gdal_grid.&lt;br /&gt;
 &lt;br /&gt;
Чтобы не быть голословными, выполним весь цикл процедур: интерполяция данных из предыдущего примера result/tops.shp при помощи gdal_grid, проверка полученного процедурного растра на «зеркальность», исправление его при помощи raster_tools. В качестве исходных данных будут использованы: result/tops.shp (источник данных для интерполяции) и result/calc.tif (для сравнения). Обработку произведём скриптом repair.py (list 11). Для работы repair.py необходим модуль modules.grid_utils и сама утилита gdal_rid.  &lt;br /&gt;
&lt;br /&gt;
list 11 - repair.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import grid_utils&lt;br /&gt;
&lt;br /&gt;
out_dir = &amp;quot;result&amp;quot;&lt;br /&gt;
shp_file = &amp;quot;result/tops.shp&amp;quot;&lt;br /&gt;
field_name = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
raster_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
grid_file = &amp;quot;result/{}.tif&amp;quot;.format(field_name)&lt;br /&gt;
repair_file = &amp;quot;result/repair.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# Интерполяция на основе shp файла&lt;br /&gt;
grid_utils(raster_file, shp_file, field_name, out_dir)&lt;br /&gt;
&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&lt;br /&gt;
# возврат &amp;quot;отремонтированного&amp;quot; растра в формате стандартного словаря&lt;br /&gt;
grid = grid.repair()&lt;br /&gt;
&lt;br /&gt;
# запись исправленного растра&lt;br /&gt;
array2raster(None, grid, repair_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта были созданы 2 растра: result/POINT_DATA.tif - результат работы gdal_grid и исправленный растр result/repair.tif. Сравним их gdalinfo лог:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/POINT_DATA.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=592x1 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/repair.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.640086707766337,-0.633172658674583)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296008.694, 7137767.175) ( 40d46'51.76&amp;quot;E, 64d18'17.78&amp;quot;N)&lt;br /&gt;
Lower Left  (  296008.694, 7137566.459) ( 40d46'52.75&amp;quot;E, 64d18'11.32&amp;quot;N)&lt;br /&gt;
Upper Right (  296387.625, 7137767.175) ( 40d47'19.88&amp;quot;E, 64d18'18.60&amp;quot;N)&lt;br /&gt;
Lower Right (  296387.625, 7137566.459) ( 40d47'20.87&amp;quot;E, 64d18'12.13&amp;quot;N)&lt;br /&gt;
Center      (  296198.159, 7137666.817) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
и в качестве контрольной пробы:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ gdalinfo result/calc.tif&lt;br /&gt;
...&lt;br /&gt;
Pixel Size = (0.064274599999999,-0.064274599999986)&lt;br /&gt;
Metadata:&lt;br /&gt;
  AREA_OR_POINT=Area&lt;br /&gt;
Image Structure Metadata:&lt;br /&gt;
  COMPRESSION=LZW&lt;br /&gt;
  INTERLEAVE=BAND&lt;br /&gt;
Corner Coordinates:&lt;br /&gt;
Upper Left  (  296007.704, 7137768.705) ( 40d46'51.68&amp;quot;E, 64d18'17.83&amp;quot;N)&lt;br /&gt;
Lower Left  (  296007.704, 7137564.891) ( 40d46'52.68&amp;quot;E, 64d18'11.27&amp;quot;N)&lt;br /&gt;
Upper Right (  296388.595, 7137768.705) ( 40d47'19.94&amp;quot;E, 64d18'18.65&amp;quot;N)&lt;br /&gt;
Lower Right (  296388.595, 7137564.891) ( 40d47'20.95&amp;quot;E, 64d18'12.08&amp;quot;N)&lt;br /&gt;
Center      (  296198.149, 7137666.798) ( 40d47' 6.31&amp;quot;E, 64d18'14.96&amp;quot;N)&lt;br /&gt;
Band 1 Block=256x256 Type=Float64, ColorInterp=Gray&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Обратите внимание на второе значение Pixel Size(ось y): у растра сгенерированного gdal_grid это значение положительное, в отличии от исходного и исправленного георастров. Что и позволяет отображать POINT_DATA.tif в гис программах нормально, несмотря на наличие зеркально отображённого через ось y массива. То же самое сообщает нам вывод метода raster2array.is_valid():&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# загрузка результатов интерполяции в raster2array&lt;br /&gt;
grid = raster2array(grid_file)&lt;br /&gt;
# проверка &amp;quot;валидности&amp;quot; массива в растре&lt;br /&gt;
print grid.is_valid()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Вывод строки:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
[True, False]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Здесь ориентация растра по оси x истинное и ложное по оси y. &lt;br /&gt;
&lt;br /&gt;
==Послесловие==&lt;br /&gt;
Заканчивая описание способов употребления raster_tools хочу сказать что инструмент будет и дальше находится в состоянии постоянного развития. По мере поступления задач буду добавлять в него какие то новые приспособления, при этом постараюсь сохранить старые методы применения (чтобы не потерять совместимость с уже завершёнными проектами). Статья описывает состояние raster_tools версии 0.4 - на текущий момент последний stable.&lt;br /&gt;
У raster_tools имеются следующие недостатки: &lt;br /&gt;
* проблемное перепроецирование векторных слоёв-шаблонов в проекцию растра, поэтому стараюсь использовать единую проекцию;&lt;br /&gt;
* обрезка по shp файлам «прибита гвоздями» к первому векторному слою;&lt;br /&gt;
* инструмент рассчитан на geotif - работа с другими растровыми форматами файлов в зачаточном состоянии;&lt;br /&gt;
* недостаточно оптимизирована работа с мультирастрами (не часто пока требуются).&lt;br /&gt;
В остальном инструмент меня устраивает, кого заинтересовал — отвечу на возникшие вопросы.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26140</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26140"/>
		<updated>2018-05-31T15:06:52Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif.&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
calc.py&lt;br /&gt;
&lt;br /&gt;
img: logs/calc_mprof.png&lt;br /&gt;
&lt;br /&gt;
calc_iter.py&lt;br /&gt;
&lt;br /&gt;
img:logs/calc_iter_mprof.png&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод в несколько раз выигрывает в потреблении памяти, но теряет в скорости расчётов. Потери скорости не очень существенны на текущем примере - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
==Трансформация==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210), (125,105), (300,300). Последний массив сохранится в растр result/resize.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Мультирастры==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Работа с точками.==&lt;br /&gt;
Не очевидный, но временами очень важный, метод препарирования георастров. Постановка задачи: запись значений точек растра с определёнными координатами в csv, БД или в виде поля в слой shp файла. Реализация последнего примера представлена в point_data_load_array.py (list 9). Исходными данными здесь выступают: георастр  result/calc.tif и векторный файл со слоем точек data/tops.shp.&lt;br /&gt;
&lt;br /&gt;
list 9 - point_data_load_array.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array&lt;br /&gt;
import ogr&lt;br /&gt;
import shutil&lt;br /&gt;
&lt;br /&gt;
raster = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# копируем тестовый shp файл с точками в каталог result&lt;br /&gt;
_filename = &amp;quot;tops&amp;quot;&lt;br /&gt;
_indir = &amp;quot;data&amp;quot;&lt;br /&gt;
_outdir = &amp;quot;result&amp;quot;&lt;br /&gt;
for _ex in [&amp;quot;dbf&amp;quot;, &amp;quot;prj&amp;quot;, &amp;quot;qpj&amp;quot;, &amp;quot;shp&amp;quot;, &amp;quot;shx&amp;quot;]:&lt;br /&gt;
    shutil.copyfile(&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_indir, _filename, _ex),&lt;br /&gt;
        &amp;quot;{0}/{1}.{2}&amp;quot;.format(_outdir, _filename, _ex),&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;{0}/{1}.shp&amp;quot;.format(_outdir, _filename)&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
raster = raster2array(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&lt;br /&gt;
# загрузка shp файла&lt;br /&gt;
_shp = ogr.Open(shp_file, update=1)&lt;br /&gt;
layer = _shp.GetLayerByIndex(0)&lt;br /&gt;
&lt;br /&gt;
# добавление в shp файл нового поля&lt;br /&gt;
# для записи выгруженных значений растра&lt;br /&gt;
new_field = &amp;quot;POINT_DATA&amp;quot;&lt;br /&gt;
if layer.FindFieldIndex(new_field, 1) &amp;lt; 1:&lt;br /&gt;
    field = ogr.FieldDefn(new_field, ogr.OFTReal)&lt;br /&gt;
    layer.CreateField(field)&lt;br /&gt;
&lt;br /&gt;
# обход циклом точек shp файла&lt;br /&gt;
for geometry in layer:&lt;br /&gt;
&lt;br /&gt;
    # определение координат точки векторного файла&lt;br /&gt;
    x, _, y, _ = geometry.GetGeometryRef().GetEnvelope()&lt;br /&gt;
&lt;br /&gt;
    # возврат значения данных точки растра&lt;br /&gt;
    # по координатам точки векторного файла&lt;br /&gt;
    raster_data = raster.get_pixel_value(float(x), float(y))&lt;br /&gt;
&lt;br /&gt;
    # сохранение выгруженных из растра данных&lt;br /&gt;
    # в новое поле shp файла&lt;br /&gt;
    geometry.SetField(new_field, raster_data)&lt;br /&gt;
    layer.SetFeature(geometry)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ходе выполнения скрипта исходный векторный файл data/tops.shp копируется в result/tops.shp, в который добавляется поле «POINT_DATA». В добавленном поле сохраняются значения точек растра по координатам геометрий векторного слоя. При помощи полученного векторного файла можно будет производить интерполяцию значений поля «POINT_DATA»(пример дальше по тексту).&lt;br /&gt;
&lt;br /&gt;
В list 9 есть одна «хитрость»:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
# сохранение numpy массива в объекте raster2array&lt;br /&gt;
raster.np_array_load()&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Такая конструкция загружает numpy массив растра непосредственно в экземпляр класса rater2array - что уменьшает время выполнения операций, увеличивая потребление памяти. Для сравнения: в репозитории есть аналогичный скрипт point_data_dont_load_array.py где данная строка отсутствует. Сравнение графиков выполнения обоих скриптов в memory_profiler выглядит следующим образом: &lt;br /&gt;
&lt;br /&gt;
point_data_load_array.py&lt;br /&gt;
&lt;br /&gt;
img: logs/point_data_load_array_mprof.png&lt;br /&gt;
&lt;br /&gt;
point_data_dont_load_array.py&lt;br /&gt;
&lt;br /&gt;
img: logs/point_data_dont_load_array_mprof.png&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26139</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26139"/>
		<updated>2018-05-31T15:01:25Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif.&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
calc.py&lt;br /&gt;
&lt;br /&gt;
img: logs/calc_mprof.png&lt;br /&gt;
&lt;br /&gt;
calc_iter.py&lt;br /&gt;
&lt;br /&gt;
img:logs/calc_iter_mprof.png&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод в несколько раз выигрывает в потреблении памяти, но теряет в скорости расчётов. Потери скорости не очень существенны на текущем примере - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
* cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
* cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
* cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
==Трансформация==&lt;br /&gt;
&lt;br /&gt;
Иногда приходится вычислять индексы, или иным способом сравнивать георастры из различных источников. Входные данные могут быть в разном масштабе и соответственно иметь разную размерность массивов исследуемой области. В результате вычисление индексов средствами numpy становится невозможным, а многие другие операции затруднительны. &lt;br /&gt;
&lt;br /&gt;
Решить подобною проблему призван класс raster2transform. При помощи него можно изменить размерность массива, или части массива, георастра, а так же сменить проекцию.&lt;br /&gt;
Для работы тестового примера resize.py (list 6) требуется установка matplotlib и графической среды пользователя, исходным георастром является result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
list 6 - resize.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, raster2transform&lt;br /&gt;
from matplotlib import pyplot as plt&lt;br /&gt;
&lt;br /&gt;
in_raster = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
out_raster = &amp;quot;result/resize.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вывод массива в matplotlib&lt;br /&gt;
def plt_show(obj):&lt;br /&gt;
    plt.title(&amp;quot;show&amp;quot;)&lt;br /&gt;
    plt.imshow(obj.array(), cmap='gray')&lt;br /&gt;
    plt.show()&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в raster2array&lt;br /&gt;
raster = raster2array(in_raster)&lt;br /&gt;
print raster.rows, raster.cols&lt;br /&gt;
&lt;br /&gt;
# кроме того возможна работа с:&lt;br /&gt;
#raster = in_raster #именем растрового файла&lt;br /&gt;
#raster = raster2array(in_raster).get_std_dict() #стандартным словарём&lt;br /&gt;
&lt;br /&gt;
# изменение размерности массива (row, col) в цикле&lt;br /&gt;
for row, col in [(253, 210), (125, 105), (300, 300)]:&lt;br /&gt;
    raster = raster2transform(raster, row, col)&lt;br /&gt;
    print raster.rows, raster.cols&lt;br /&gt;
    plt_show(raster)&lt;br /&gt;
&lt;br /&gt;
# сохранение растра c последней размерностью массива&lt;br /&gt;
raster.save(out_raster)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате работы скрипта 3 раза отобразится окно matplotlib.pyplot с изображением массива растра в следующих размерностях: (253,210), (125,105), (300,300). Последний массив сохранится в растр result/resize.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
==Мультирастры==&lt;br /&gt;
&lt;br /&gt;
Для вычисления индексов удобно работать с одноканальными растрами - представляя каждый канал как отдельно взятую сущность. Но иногда требуется создавать и работать с многоканальными конструкциями. Для это создана пара мультиканальных классов: &lt;br /&gt;
&lt;br /&gt;
* raster2multiarray - Класс умеющий изменять очерёдность и количество каналов, при этом преобразующий многоканальный растр в стандартный словарь расширенного типа. От обычного он отличается тем что в поле «array» сохраняется не двухмерный (x, y), а трёхмерный numpy массив с индексом (bands, x, y). Для определения типа массива добавлено поле «multi_type» - принимающее значения: None - с массивом уже указанного индекса и «cv» - с индексом (x, y, bands). Массив типа multi_type = «cv» аналогичен возвращаемому функцией cv2.imread. Кроме того у raster2multiarray имеется набор методов обрезки растра аналогичных raster2array.&lt;br /&gt;
&lt;br /&gt;
* multiarray2multiraster - Класс сохраняющий многоканальный стандартный словарь в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Предлагаю два варианта использования данной пары классов, исходным растром для примеров послужит data/multi.tif:&lt;br /&gt;
&lt;br /&gt;
===Изменение последовательности каналов.===&lt;br /&gt;
&lt;br /&gt;
Для данного примера в rgb мультирастре переставим местами 1-й и 3-й каналы. Тестовый скрипт представлен в multi_rebands.py (list 7). &lt;br /&gt;
&lt;br /&gt;
list 7 - multi_rebands.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_rebands.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# и изменение последовательности каналов 1-3, 2-2, 3-1&lt;br /&gt;
img = raster2multiarray(img_in, 3, 2, 1)&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
img = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# cохранение многоканального стандартого словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, img)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результатом выполнения будет создание result/multi_rebands.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
===Обработка муьтирастров в opencv.===&lt;br /&gt;
&lt;br /&gt;
Теперь усложним задачу: удалим альфа канал мультирастра, передадим массив на обработку opencv и сохраним полученный результат. Для этого примера необходимо установить python opencv 2 или 3. Тестовый скрипт представлен в multi_opencv.py (list 8).&lt;br /&gt;
&lt;br /&gt;
list 8 - multi_opencv.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2multiarray, multiarray2multiraster&lt;br /&gt;
import cv2&lt;br /&gt;
&lt;br /&gt;
img_in = 'data/multi.tif'&lt;br /&gt;
img_out = 'result/multi_opencv.tif'&lt;br /&gt;
&lt;br /&gt;
# загрузка многоканального в объект raster2multiarray&lt;br /&gt;
# для обработки через cv2.bilateralFilter необходима загрузка только 1,2,3 канала&lt;br /&gt;
img = raster2multiarray(img_in, 1, 2, 3)&lt;br /&gt;
&lt;br /&gt;
# установка типа возвращаемого многоканального массива&lt;br /&gt;
# в формат opencv&lt;br /&gt;
img.multi_type = &amp;quot;cv&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка типа данных возвращаемого массива как uint8&lt;br /&gt;
# необходимо для обработки данных в opencv&lt;br /&gt;
img.codage = np.uint8&lt;br /&gt;
&lt;br /&gt;
# выгрузка многоканального стандартого словаря&lt;br /&gt;
std_dict = img.get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# работа в OpenCV c многоканальным массивом&lt;br /&gt;
std_dict[&amp;quot;array&amp;quot;] = cv2.bilateralFilter(std_dict[&amp;quot;array&amp;quot;],9,75,75)&lt;br /&gt;
&lt;br /&gt;
# сохранение многоканального стандартного словаря&lt;br /&gt;
# в мультирастр&lt;br /&gt;
multiarray2multiraster(img_out, std_dict)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат будет сохранён в result/multi_opencv.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26138</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26138"/>
		<updated>2018-05-31T14:48:45Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster(raster2array)''' - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform(raster2array)''' - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc(raster2array)''' - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray(raster2array)''' - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif.&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
calc.py&lt;br /&gt;
&lt;br /&gt;
img: logs/calc_mprof.png&lt;br /&gt;
&lt;br /&gt;
calc_iter.py&lt;br /&gt;
&lt;br /&gt;
img:logs/calc_iter_mprof.png&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод в несколько раз выигрывает в потреблении памяти, но теряет в скорости расчётов. Потери скорости не очень существенны на текущем примере - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;br /&gt;
&lt;br /&gt;
== Вырезание области растра. ==&lt;br /&gt;
&lt;br /&gt;
Иногда растровые вычисления необходимо производить только с некоторой выделенной областью георастра. Для «фигурного» вырезания областей, ограниченных координатами точек или bbox-ом  полигонов, у raster2array есть ряд методов:&lt;br /&gt;
&lt;br /&gt;
cut_area(координаты точек) - метод вырезает область растра по координатам (не менее 2-х точек).&lt;br /&gt;
&lt;br /&gt;
cut_shp_file(имя shp файла) - метод вырезает растр по полигонам первого слоя shp файла.&lt;br /&gt;
&lt;br /&gt;
cut_ogr_geometry(wkt, geojson, gml, wkb) — метод вырезает растр по полигону загруженной геометрии.&lt;br /&gt;
&lt;br /&gt;
Все перечисленные методы возвращают «стандартный словарь», так как они изменяют размерность массива растра, делая необходимым изменение «transorm» у сохраняемого георастра.&lt;br /&gt;
&lt;br /&gt;
Стандартный словарь применим и в растровом калькуляторе, для подобных вычислений необходимо вернуть numpy массив по ключу «array» list 1.1&lt;br /&gt;
&lt;br /&gt;
list 1.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов в формате стандартного словаря&lt;br /&gt;
# выгрузка аналогична методам обрезки, но для&lt;br /&gt;
# всего исходного растра&lt;br /&gt;
red = raster2array(in_file, 1).get_std_dict()&lt;br /&gt;
green = raster2array(in_file, 2).get_std_dict()&lt;br /&gt;
blue = raster2array(in_file, 3).get_std_dict()&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()[&amp;quot;array&amp;quot;]&lt;br /&gt;
g = green()[&amp;quot;array&amp;quot;]&lt;br /&gt;
b = blue()[&amp;quot;array&amp;quot;]&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI (как в list 1)&lt;br /&gt;
&lt;br /&gt;
........&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в стандартный словарь&lt;br /&gt;
out_std_dict = red&lt;br /&gt;
out_std_dict[&amp;quot;array&amp;quot;] = calc&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out_std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим работу каждого метода обрезки растра:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_area ===&lt;br /&gt;
&lt;br /&gt;
Позволяет обрезать растр по набору координат точек. Применяется когда необходимо обрезать область растра по массиву точек - для дальнейшей обработки. Пример использования приведён в cut_coords.py (list 3), в качестве исходных данных используется result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
list 3 - cut_coords.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_coords.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по координатам&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_area(&lt;br /&gt;
    (296153.369,7137678.937),&lt;br /&gt;
    (296203.959,7137570.986),&lt;br /&gt;
    (296256.938,7137645.476)&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат выполнения метода сохраняется в out: result/cut_coords.tif&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_shp_file ===&lt;br /&gt;
&lt;br /&gt;
Часто необходимо обрезать растр по геометрии слоя shp файла. Пример выполнения такой задачи приведён в cut_shp.py (list 4). Помимо исходного георастра  result/calc.tif , скрипт использует шаблона обрезки - data/cut.shp.&lt;br /&gt;
&lt;br /&gt;
list 4 - cut_shp.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
&lt;br /&gt;
shp_file = &amp;quot;data/cut.shp&amp;quot;&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_shp.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону shp файла&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_shp_file(shp_file)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Результат сохраняется в георастр result/cut_shp.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;br /&gt;
&lt;br /&gt;
Обратите внимание что растр обрезан непосредственно по полигону, а не только по координатам bbox-а геометрии.&lt;br /&gt;
&lt;br /&gt;
=== Метод cut_ogr_geometry ===&lt;br /&gt;
&lt;br /&gt;
Применяется если необходима обрезка георастра по геометрия в формате wkt, geojson, gml или wkb. Наиболее типичный способ использования - это вырезание растра на по wkt геометрии возвращённой из postgis.&lt;br /&gt;
&lt;br /&gt;
Для выполнения примера следует провести подготовку(все примеры работы с БД приведены для linux): &lt;br /&gt;
* Установить postgresql и расширение postgis. &lt;br /&gt;
* В СУБД создать роль из под которой возможен логин в БД для загрузки дампа:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
# su - postgres&lt;br /&gt;
$ psql&lt;br /&gt;
create role gis with login password 'gis';&lt;br /&gt;
create database dok_example owner gis;&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Имя пользователя, пароль и имя базы можно использовать произвольные - но тогда необходимо будет изменить в list 5 переменные: dbname, dbuser, dbpass.&lt;br /&gt;
* Создать расширение postgis в БД.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ psql -d doc_example&lt;br /&gt;
create extension postgis&lt;br /&gt;
ctrl-d&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Развернуть дамп из data/crowns.sql&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
psql -d doc_example &amp;lt; data/crowns.sql&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* Проверить наличие python модуля psycopg2 - драйвера postgresql.(необходим для интерфейса запросов  modules.db_interface)&lt;br /&gt;
&lt;br /&gt;
После успешного завершения подготовительного этапа можно выполнять тестовый пример cut_wkt.py (list 5)&lt;br /&gt;
&lt;br /&gt;
list 5 - cut_wkt.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#! /usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
from modules import psql&lt;br /&gt;
&lt;br /&gt;
# загрузка растра в объект raster2array&lt;br /&gt;
in_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/cut_wkt.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# установка параметров подключения в БД&lt;br /&gt;
dbhost = &amp;quot;localhost&amp;quot;&lt;br /&gt;
dbname = &amp;quot;dok_example&amp;quot;&lt;br /&gt;
dbuser = &amp;quot;gis&amp;quot;&lt;br /&gt;
dbpass = &amp;quot;gis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# параметры поиска полигона в БД&lt;br /&gt;
geom_table = &amp;quot;crowns&amp;quot;&lt;br /&gt;
geom_id = 55775&lt;br /&gt;
&lt;br /&gt;
# запрос в БД возвращающий полигон в формате WKT&lt;br /&gt;
SQL = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
select ST_AsText(wkb_geometry)&lt;br /&gt;
from {0}&lt;br /&gt;
where ogc_fid = {1}&lt;br /&gt;
&amp;quot;&amp;quot;&amp;quot;.format(&lt;br /&gt;
    geom_table,&lt;br /&gt;
    geom_id&lt;br /&gt;
)&lt;br /&gt;
_psql = psql(&lt;br /&gt;
    dbhost=dbhost,&lt;br /&gt;
    dbname=dbname,&lt;br /&gt;
    dbuser=dbuser,&lt;br /&gt;
    dbpass=dbpass&lt;br /&gt;
)&lt;br /&gt;
_psql.sql(SQL)&lt;br /&gt;
wkt_geom = _psql.fetchone()[0]&lt;br /&gt;
_psql.close()&lt;br /&gt;
&lt;br /&gt;
# вырезание области растра по полигону WKT&lt;br /&gt;
# и сохранение в формате стандартного словаря&lt;br /&gt;
std_dict = raster2array(in_file).cut_ogr_geometry(wkt_geom)&lt;br /&gt;
&lt;br /&gt;
# сохранеие стандартного словаря в растр&lt;br /&gt;
array2raster(None, std_dict, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения примера должен быть создан result/cut_wkt.tif.&lt;br /&gt;
&lt;br /&gt;
img:&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26137</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26137"/>
		<updated>2018-05-31T14:21:11Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== 1. Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pip2.7 install --user git+https://github.com/oldbay/raster_tools&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''raster_tools''' состоит из следующих классов:&lt;br /&gt;
&lt;br /&gt;
'''raster2array''' - Базовый класс, отвечающий за весь функционал загрузки растра и сохранение numpy массива выбранного канала(band). Выгруженный из растра массив может быть преобразован методами данного класса. &lt;br /&gt;
&lt;br /&gt;
'''array2raster'''(raster2array) - Субкласс, отвечающий за сохранение обработанного массива в файле георастра. Он так же может сформировать виртуальный растр в памяти с возможностью обработки методами базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2transform'''(raster2array) - Субкласс, отвечающий за трансформацию растра: изменение размерности массива и перепроецирование. Так же есть поддержка методов базового класса.&lt;br /&gt;
&lt;br /&gt;
'''raster2calc'''(raster2array) - Класс итерационного калькулятора. Он не наследует базовый класс raster2array, но использует некоторые его методы опосредованно.&lt;br /&gt;
&lt;br /&gt;
'''raster2multiarray'''(raster2array) - Класс обработки мультирастров. Позволяет миксовать каналы мультиканального растра и обрабатывать его некоторыми методами raster2array.&lt;br /&gt;
&lt;br /&gt;
'''multiarray2multiraster''' - Класс сохранения массивов, обработанных методами raster2multiarray, в мультиканальный растр.&lt;br /&gt;
&lt;br /&gt;
Основной смысл существования всего этого «зоопарка» классов - это загрузка, обработка и выгрузка двухмерного numpy массива георастров. Помимо объекта 2-х мерного numpy массива некоторые методы raster2array позволяют выгружать данные в формате самоназвоного «стандартного словаря», имеющего следующий вид:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
    &amp;quot;array&amp;quot;: объект numpy.ndarray,&lt;br /&gt;
    &amp;quot;shape&amp;quot;: кортеж (rows(Y), cols(X)) = numpy.ndarray.shape = (gdal.dataset.RasterYSize(), gdal.dataset.RasterXSize()),&lt;br /&gt;
    &amp;quot;transform&amp;quot;: кортеж gdal.dataset.GetGeoTransform(),&lt;br /&gt;
    &amp;quot;projection&amp;quot;: объект gdal.dataset.GetProjection()&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;  &lt;br /&gt;
&lt;br /&gt;
Эта конструкция несёт в себе всю необходимую информацию для создания нового георастра, отличного от исходного.&lt;br /&gt;
&lt;br /&gt;
Углубляться в подробное описание стрктуры классов и методов raster_tools не вижу необходимости - достаточно полная базовая документация есть в README.rst на [https://github.com/oldbay/raster_tools https://github.com/oldbay/raster_tools] . В данной статье хотелось бы показать «боевое» применение raster_tools на практике, в том виде как сам его в проектах «готовлю».&lt;br /&gt;
&lt;br /&gt;
Для этих экспериментов был создан gis репозиторий с тестовыми данными , загрузить которые можно командой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone  https://gitlab.com/oldbay/raster_tools_examples.git&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В ветке по умолчанию (master) , расположены только тестовые скрипты и исходные данные. Чтобы заранее изучить результаты тестов, нужно перейти в ветку result:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git checkout origin/result&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Тестовый репозирорий состоит из:&lt;br /&gt;
* Корень: содержит тестовые примеры - выполнение которых необходимо производить из текущего каталога;&lt;br /&gt;
* Каталог data: содержит исходные данные для экспериментов;&lt;br /&gt;
* Каталог logs: содержит результаты тестов расхода памяти и времени выполнения (branch result);&lt;br /&gt;
* Каталог module: содержит дополнительные python модули, необходимые для выполнение некоторых тестовых скриптов(в статье не описаны);&lt;br /&gt;
* Каталог results: содержит результаты экспериментов (branch result).&lt;br /&gt;
&lt;br /&gt;
== 2. Растровый калькулятор. ==&lt;br /&gt;
&lt;br /&gt;
Первоначально raster_tools был частью растрового калькулятора, сейчас отдельный проект raster_calc, поэтому исторически начнём с вычислений.&lt;br /&gt;
 &lt;br /&gt;
Пример простого растрового калькулятора представлен в calc.py (list 1) . В данном скрипте мультирастр разбирается на спектральные каналы, после чего вычисляется вегетативный индекс на основе rgb - TGI([https://gist.github.com/merkato/0cd894f19518496171afd7425e09ed88 украдено отсюда]), Источником данных является data/multi.tif.&lt;br /&gt;
&lt;br /&gt;
list 1 - calc.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# сохранение numpy массивов каналов в переменные.&lt;br /&gt;
r = red()&lt;br /&gt;
g = green()&lt;br /&gt;
b = blue()&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
calc = np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# сохранение вычисленного массива в растр.&lt;br /&gt;
array2raster(red, calc, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
В результате выполнения calc.py создается растр result/calc.tif.&lt;br /&gt;
&lt;br /&gt;
Img:&lt;br /&gt;
&lt;br /&gt;
У метода есть существенный минус - высокое потребление памяти. Фактически в памяти , на пике потребления, присутствуют сразу 4 массива растров: каналов r, g, b и вычисляемого индекса. При работе с большими георастрами это часто неприемлемо. Поэтому был разработан итерационный метод работы растрового калькулятора. Данный метод работает с растром посекторно в цикле.  При таких вычислениях сильно снижается потребление памяти, но падает производительность.&lt;br /&gt;
&lt;br /&gt;
Итерационный калькулятор реализован в calc_iter.py (list 2). В отличии от простого калькулятора здесь формула вычислений(в формате lambda) и переменные для вычислений(в виде объектов raster2array) передаются классу raster2calc.&lt;br /&gt;
&lt;br /&gt;
list 2 - calc_iter.py&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;python&amp;quot;&amp;gt;&lt;br /&gt;
#!/usr/bin/python2&lt;br /&gt;
# -*- coding: utf-8 -*-&lt;br /&gt;
&lt;br /&gt;
from raster_tools import raster2array, array2raster, raster2calc&lt;br /&gt;
import numpy as np&lt;br /&gt;
&lt;br /&gt;
in_file = &amp;quot;data/multi.tif&amp;quot;&lt;br /&gt;
out_file = &amp;quot;result/calc_iter.tif&amp;quot;&lt;br /&gt;
&lt;br /&gt;
# загрузка каналов&lt;br /&gt;
red = raster2array(in_file, 1)&lt;br /&gt;
green = raster2array(in_file, 2)&lt;br /&gt;
blue = raster2array(in_file, 3)&lt;br /&gt;
&lt;br /&gt;
# описание формулы вычисления TGI&lt;br /&gt;
calc_func = lambda r,g,b: np.choose(&lt;br /&gt;
    np.not_equal(g-r+b-255.0, 0.0),&lt;br /&gt;
    (&lt;br /&gt;
        -9999.0,&lt;br /&gt;
        np.subtract(&lt;br /&gt;
            g,&lt;br /&gt;
            np.multiply(0.39, r),&lt;br /&gt;
            np.multiply(0.61, b)&lt;br /&gt;
        )&lt;br /&gt;
    )&lt;br /&gt;
)&lt;br /&gt;
&lt;br /&gt;
# вычисление TGI&lt;br /&gt;
# и сохраниение результата в формате&lt;br /&gt;
# стандартного словаря&lt;br /&gt;
calc = raster2calc()&lt;br /&gt;
out = calc(&lt;br /&gt;
        calc_func,&lt;br /&gt;
        r=red,&lt;br /&gt;
        g=green,&lt;br /&gt;
        b=blue&lt;br /&gt;
    )&lt;br /&gt;
&lt;br /&gt;
# сохраниение стандартного словаря в растр.&lt;br /&gt;
array2raster(None, out, out_file)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
raster2calc возвращает «стандартный словарь» преобразуемый классом array2raster в файл result/calc_iter.tif.&lt;br /&gt;
&lt;br /&gt;
Если выполнить calc.py и calc_iter.py в обёртке memory_profiler - получаем графики потребления памяти:&lt;br /&gt;
&lt;br /&gt;
calc.py&lt;br /&gt;
&lt;br /&gt;
img: logs/calc_mprof.png&lt;br /&gt;
&lt;br /&gt;
calc_iter.py&lt;br /&gt;
&lt;br /&gt;
img:logs/calc_iter_mprof.png&lt;br /&gt;
&lt;br /&gt;
Видно что итерационный метод в несколько раз выигрывает в потреблении памяти, но теряет в скорости расчётов. Потери скорости не очень существенны на текущем примере - но при массовой обработке небольших георастров, бывает выгоднее пожертвовать памятью.&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26136</id>
		<title>Практика использования raster tools</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%9F%D1%80%D0%B0%D0%BA%D1%82%D0%B8%D0%BA%D0%B0_%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D1%8C%D0%B7%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_raster_tools&amp;diff=26136"/>
		<updated>2018-05-31T13:32:11Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: Новая страница: «{{Статья|Черновик}} {{Аннотация|В статье рассматриваются примеры практического использов…»&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
{{Аннотация|В статье рассматриваются примеры практического использования набора растровых инструментов raster_tools.}}&lt;br /&gt;
&lt;br /&gt;
== 1. Знакомство с raster_tools ==&lt;br /&gt;
&lt;br /&gt;
В течении продолжительного времени развиваю инструментарий для препарирования георастров. Который является набором рецептов упрощающих взаимодействие с гибкой но сложной структурой python gdal. К сегодняшнему времени rater_tools напоминает некий «швейцарский нож» с разнообразным функционалом. &lt;br /&gt;
Код проекта расположен на [https://github.com/oldbay/raster_tools 'github'] , самый простой способ его установки в каталоге пользователя - при помощи pip:&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%90%D1%82%D0%BC%D0%BE%D1%81%D1%84%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D0%BA%D0%BE%D1%80%D1%80%D0%B5%D0%BA%D1%86%D0%B8%D1%8F_%D0%BF%D0%BE_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%83_DOS&amp;diff=22387</id>
		<title>Атмосферная коррекция по методу DOS</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%90%D1%82%D0%BC%D0%BE%D1%81%D1%84%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D0%BA%D0%BE%D1%80%D1%80%D0%B5%D0%BA%D1%86%D0%B8%D1%8F_%D0%BF%D0%BE_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%83_DOS&amp;diff=22387"/>
		<updated>2015-08-19T20:13:21Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
=='''Анотация'''==&lt;br /&gt;
&lt;br /&gt;
Недавно была защищена магистерская диссертация по ГИС тематике, решил выдержки из данной работы опубликовать в виде цикла статей. В первой статье рассмотрим атмосферную коррекцию по методу DOS (Dark Object Subtraction). В конце статьи представлен готовый программный инструментарий для выполения атмосферной коррекции.&lt;br /&gt;
&lt;br /&gt;
=='''Подготовка геоданных'''==&lt;br /&gt;
&lt;br /&gt;
Среди источников геоданных использовались данные USGS (Геологической Службы Соединённых Штатов) [1] доступных для свободного скачивания [2]. Данные с этих ресурсов представлены в формате GeoTIFF в виде непрерывных наборов сцен для различных районов мира. Представленные на ресурсах геоданные соответствуют уровню обработки LG1: «сырые геоданные» не конвертированные в значения излучения на сенсоре. Для самостоятельного проведения конвертации и атмосферной коррекции - доступны файлы настройки спутниковых сенсоров с набором ряда параметров: минимумы и максимумы пиксельной яркости на изображении; минимумы и максимумы излучения на датчиках; минимумы и максимумы отражения излучения от поверхности земли (Landsat 8) и многое другое. Кроме данных настройки спутниковых датчиков в архиве присутствуют несколько файлов в формате GeoTIFF, распределённых по номерам каналов, количество и состав которых для разных спутников (Landsat 5,7,8) различный (Таблица 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Таблица 1 — Спутники и используемые в работе каналы&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 !Спутник и датчик !! Номер канала (band) !! Название спектра !! Длинны волн (нм)&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Landsat 5 TM&lt;br /&gt;
 |1 || Blue - Синий || 450–520&lt;br /&gt;
 |-&lt;br /&gt;
 |2 || Green - Зелёный || 520–600&lt;br /&gt;
 |-&lt;br /&gt;
 |3 || Red - Красный || 630–690&lt;br /&gt;
 |-&lt;br /&gt;
 |4 || NIR — Ближний ИК || 760–900&lt;br /&gt;
 |-&lt;br /&gt;
 |5 || SWIR1 — Средний ИК 1 || 1550–1750&lt;br /&gt;
 |-&lt;br /&gt;
 |7 || SWIR2 — Средний ИК 2 || 2080–2350&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Landsat 7 ETM+&lt;br /&gt;
 |1 || Blue - Синий || 450–520&lt;br /&gt;
 |-&lt;br /&gt;
 |2 || Green - Зелёный || 520–600&lt;br /&gt;
 |-&lt;br /&gt;
 |3 || Red - Красный || 630–690&lt;br /&gt;
 |-&lt;br /&gt;
 |4 || NIR — Ближний ИК || 770–900&lt;br /&gt;
 |-&lt;br /&gt;
 |5 || SWIR1 — Средний ИК 1 || 1550–1750&lt;br /&gt;
 |-&lt;br /&gt;
 |7 || SWIR2 — Средний ИК 2 || 2080–2350&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Lansat 8 Oli&lt;br /&gt;
 |2 || Blue - Синий || 450—515&lt;br /&gt;
 |-&lt;br /&gt;
 |3 || Green - Зелёный || 525—600&lt;br /&gt;
 |-&lt;br /&gt;
 |4 || Red - Красный || 630—680&lt;br /&gt;
 |-&lt;br /&gt;
 |5 || NIR — Ближний ИК || 845—885&lt;br /&gt;
 |-&lt;br /&gt;
 |6 || SWIR1 — Средний ИК 1 || 1560—1660&lt;br /&gt;
 |-&lt;br /&gt;
 |7 || SWIR2 — Средний ИК 2 || 2100—2300&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Как видно из таблицы, шесть наиболее используемых «спектров» находятся у разных спутников в сходном диапазоне частот. Поэтому, для удобства использования терминологии, вместо указания спутниковых каналов в дальнейшем будем использовать самоназвание спектров: BLUE - синий, GREEN - зелёный, RED - красный, NIR - ближний инфракрасный, SWIR1 - средний инфракрасный 1, SWIR2 - средний инфракрасный 2 - вне зависимости от спутника и применять к ним одинаковый набор вычислений.&lt;br /&gt;
&lt;br /&gt;
Как уже упоминалось, геоданные по всем каналам предоставлены уровнем обработки LG1 - в сыром виде, это означает что предоставленные канальные GeoTIFF не более чем спозиционированные на местности яркостные «фотографии», которые, в таком виде, не могут быть использованы для ГИС исследований. Поэтому данные уровня обработки LG1 необходимо нормализовать - то есть провести конвертацию значений яркости в показатели излучения на сенсоре и атмосферную коррекцию.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Конвертация значений яркости исходного GeoTIFF в показатели излучения на сенсоре'''==&lt;br /&gt;
&lt;br /&gt;
Теоретические основы процесса конвертирования подробно описаны в статье [http://gis-lab.info/qa/dn2radiance.html 'Конвертация данных TM, ETM+ в показатели излучения на сенсоре'], потому коснёмся только практической реализации процесса.&lt;br /&gt;
&lt;br /&gt;
Конвертирование является первым этапом нормализации сырых геоданных и представляет из себя математическую операцию перевода значения яркости пикселей геоснимка в значения радиации поступившей на датчики спутника. Для такого перевода в комплекте данных Landsat присутствует файл коррекции _MTL.txt, предельные значения из которого и используются на этом этапе обработки геоснимка.&lt;br /&gt;
&lt;br /&gt;
Для проведения работы использовалась стандартная, описанная в документации NASA, формула (1) перевода яркости в значение top of atmosphere radiance (TOA radiance) &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::[[Файл:F_01.png]]    (1)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
где:&lt;br /&gt;
::''Lλ'' - спектральная радиация, пришедшая на сенсор спутника;&lt;br /&gt;
::''DNcal'' - значения яркости пикселя сырого геоснимка;&lt;br /&gt;
::''Qcalmin'' - минимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''Qcalmax'' - максимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''LMINλ'' - минимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка;&lt;br /&gt;
::''LMAXλ'' - максимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Кроме того для вычисления TOA radiance можно использовать упрощенную формулу (2) Thome et al., 1994 [3], Lu et al 2002 [4].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::''Lλ = DNcal × Gainλ + Baisλ''    (2)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
где:&lt;br /&gt;
::''Lλ'' - спектральная радиация, пришедшая на сенсор спутника;&lt;br /&gt;
::''DNcal'' - значения яркости пикселя сырого геоснимка;&lt;br /&gt;
::''Gainλ'' - усиление значения радиации относительно яркости исходного геоснимка;&lt;br /&gt;
::''Baisλ'' - смещение значения радиации относительно яркости исходного геоснимка.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
После обсчёта каждого пикселя геоснимка с использованием данной формулы, получаем матрицу значений c плавающей точкой - нормализованных геоданных. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Атмосферная коррекция'''==&lt;br /&gt;
&lt;br /&gt;
Следующим этапом нормализации геоданных является уменьшение влияния атмосферы на снимок и перевод значений радиации, дошедшей до сенсоров спутника (TOA radiance), в значения реально отражённого от земли спектрального излучения солнечного света.&lt;br /&gt;
&lt;br /&gt;
Материалы данного и последующих разделов, в некоторой степени, перекликаются со статьёй [http://gis-lab.info/qa/atcor.html &amp;quot;Атмосферная коррекция данных Landsat/ETM+ (COST метод)&amp;quot;], но в отличии от неё ориентированы на пакетную обработку ДДЗ из нескольких источников.&lt;br /&gt;
&lt;br /&gt;
Влияние атмосферы на геоснимок проявляется в целом ряде факторов: угол падения и отражения солнечных лучей, прозрачность атмосферы, газовый фактор и дымка (Рисунок 1).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Файл:Dos_img_1.jpg]]&lt;br /&gt;
&lt;br /&gt;
Рисунок 1 — Факторы, влияющие на попадание отраженной солнечной радиации на сенсоры спутника&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Для дальнейших исследований необходимо провести оптическую коррекцию (нормализацию) данных геоснимка методом Dark Object Subtraction (DOS), впервые представленным Chavez (1996) [5]. Суть метода состоит в нахождении яркости однопроцентно тёмного объекта геоснимка с последующей коррекцией минимума значений каждого пикселя изображения, относительно спектральной яркости найденного объекта.&lt;br /&gt;
&lt;br /&gt;
Есть два основных способа поиска 1% темного объекта (Dark Object) для метода DOS:&lt;br /&gt;
# эмпирический метод - подразумевает поиск значений в ручном режиме, например, с использованием инструмента гистограмма в QGIS, где изменяя нижний порог яркости гистограммы постепенно находим примерное значение яркости искомого тёмного объекта;&lt;br /&gt;
#вычислительный метод подразумевает, что суммарная яркость (от 0 до n) однопроцентно тёмного объекта будет соответствовать 0.01% от суммарной яркости всех пикселей геоснимка Sobrino et al., 2004 [6].&lt;br /&gt;
В данной работе успешно применяли метод (2), хорошо показавший себя при обработке большого количества геоснимков исследуемого района.&lt;br /&gt;
&lt;br /&gt;
После определения яркости Dark Object (в дальнейших вычислениях будем обозначать его как DNmin), производим атмосферную коррекцию по методу DOS в несколько этапов:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====1.Вычисляем значение радиации, соответствующее значению яркости 1% темного объекта (расчёт производится по аналогии с TOA radiance), по формуле (3).====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::[[Файл:Dos_f_03.png]]    (3)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
где:&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта;&lt;br /&gt;
::''DNmin'' - значения яркости пикселя 1% тёмного объекта;&lt;br /&gt;
::''Qcalmin'' - минимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''Qcalmax'' - максимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''LMINλ'' - минимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка;&lt;br /&gt;
::''LMAXλ'' - максимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка.    &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Или с использованием упрощённой формы (4).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::''Lλmin = DNmin × Gainλ + Baisλ'' (4)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
где:&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта;&lt;br /&gt;
::''DNmin'' - значения яркости пикселя 1% тёмного объекта;&lt;br /&gt;
::''Gainλ'' - усиление значения радиации относительно яркости 1% тёмного объекта;&lt;br /&gt;
::''Baisλ'' - смещение значения радиации относительно яркости 1% тёмного объекта.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====2.Рассчитываем коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта по формуле (5).====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::[[Файл:Dos_f_05.png]] (5)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
где:&lt;br /&gt;
::''L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' - коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта;&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''E&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;'' - коэффициент солнечного внеатмосферного спектрального излучения (явно представлен как табличные данные и учитывается при калибровке датчиков Landsat 5 и 7 , для Landsat 8 дополнительно вычисляется);&lt;br /&gt;
::''θ'' - зенитное расстояние для солнца в радианах;&lt;br /&gt;
::''T&amp;lt;sub&amp;gt;Z&amp;lt;/sub&amp;gt;'' - мера прохождения излучения от солнца до земли, в методе DOS2, принимается равным cosθ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====3.Вычисляем значение атмосферной дымки (hazing) по формуле (6).====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::''Lλhaze = Lλmin - L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' (6)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
где:&lt;br /&gt;
::''Lλhaze'' - значение атмосферной дымки (hazing);&lt;br /&gt;
::''L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' - коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта;&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====4.Рассчитываем атмосферно скорректированные значения отражённой солнечной радиации по формуле (7).====&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::[[Файл:Dos_f_07.png]] (7)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
где:&lt;br /&gt;
::''ρλ'' - атмоферно скорректированные значения отражённой солнечной радиации;&lt;br /&gt;
::''Lλ'' - значения радиации пришедшей на сенсор спутника;&lt;br /&gt;
::''Lλhaze'' - значение атмосферной дымки (hazing);&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''E&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;'' - коэффициент солнечного внеатмосферного спектрального излучения (явно представлен как табличные данные и учитывается при калибровке датчиков Landsat 5 и 7 , для Landsat 8 дополнительно вычисляется);&lt;br /&gt;
::''θ'' - зенитное расстояние для солнца в радианах;&lt;br /&gt;
::''T&amp;lt;sub&amp;gt;Z&amp;lt;/sub&amp;gt;'' - мера прохождения излучения от солнца до земли, в методе DOS2, принимается равным cosθ.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Особенности работы с растрами спутника Landsat 8'''==&lt;br /&gt;
&lt;br /&gt;
Если часть сцен сняты спутником Landsat 8 датчик Oli, необходимость их сравнения со сценами спутников lansat5 (датчик TM) и landsat8 (датчик ETM+). В данном контексте известна проблема применения стандартных методов атмосферной коррекции для нового спутника: дело в том, что калибровка датчиков Oli Landsat 8 производится без учёта значений коэффициента солнечного внеатмосферного спектрального излучения Eo (Sobrino et al., 2004) [6] или ,в других источниках, Esun. Вместо использования данного коэффициента, в файл корректировки _MTL.txt, были добавлены некоторые новые спектральные параметры: REFLECTANCE_MULT_BAND - усиление значения отражения и REFLECTANCE_ADD_BAND - смещение значения отражения для каждого из спектральных датчиков. В результате, по задумке авторов изменений, расчет TOA reflectance для Landsat 8 должен производится по формуле (8).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::''ρλ' = MρQcal+ Aρ'' (8)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
где: &lt;br /&gt;
::''ρλ''' - значение верхнеатмосфеного планетарного отражения радиации (TOA reflectance), без учёта коррекции по углу падения и отражения солнечных лучей;&lt;br /&gt;
::''Mρ'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_MULT_BAND_x, где x это номер канала) - усиление значения отражения;&lt;br /&gt;
::''Aρ'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_ADD_BAND_x,где x это номер канала) - смещение значения отражения;&lt;br /&gt;
::''Qcal'' - значения яркости пикселя сырого геоснимка (DN).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
А коррекция TOA reflectance с учётом угла падения и отражения солнечных лучей вычисляется по формуле (9).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::[[Файл:Dos_f_09.png]] (9)                               &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
где: &lt;br /&gt;
::''ρλ'' - значение верхнеатмосфеного планетарного отражения радиации (TOA reflectance), c учётом коррекции по углу падения и отражения солнечных лучей;&lt;br /&gt;
::''θSE'' - высота солнца над горизонтом. Доступна в файле _MTL.txt в параметре (SUN_ELEVATION);&lt;br /&gt;
::''θSZ'' - зенитное расстояние; θSZ = 90° - θSE.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Сообщество разработчиков свободной GIS GRASS указывает на одинаковые значения REFLECTANCE_MULT_BAND и REFLECTANCE_ADD_BAND для всех каналов снимка [8], что не может быть в реальности. Данная группа разработчиков в своём модуле нормализации и атмосферной коррекции i.landsat.toar применяет к георастрам, снятым при помощи датчиков Oli Landsat 8, те же математические методы, что для TM Landsat 5 и ETM+ Landsat 7, а недостающий коэффициент Eo (Esun) рассчитывает по формуле (10).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::[[Файл:Dos_f_10.png]] (10)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
где:&lt;br /&gt;
::''Esun'' - (E0) вычисленный коэффициент солнечного внеатмосферного спектрального излучения;&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''RADIANCE_MAXIMUM'' - каналоспецифичный мультипликативный расчётный фактор для (RADIANCE_MAXIMUM_x, где x это номер канала) - максимально возможное значение поступающей на сенсор радиации;&lt;br /&gt;
::''REFLECTANCE_MAXIMUM'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_MAXIMUM_x, где x это номер канала) - максимальное значение радиации, отражённой от поверхности земли.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ещё одной особенностью Landsat8 стало уменьшение чувствительности каналов RED, NIR и SWIR1 относительно Landsat 7 и 5 , что приводит к изменению значений, вычисляемых с использованием данных спектров, индексов.&lt;br /&gt;
&lt;br /&gt;
Данную проблему пытался решить Neil Flood, 2014 [9] введением дополнительных, рассчитанных им эмпирическим путём, коэффициентов для каждого канала геоснимка. В результате, коррекция значений TOA reflectance Landsat8 в значения для того же региона и тех же спектров Landsat7, приобретает вид формулы (11).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
::''ρETM+ = c0 + c1 × ρOLI'' (11)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
где:&lt;br /&gt;
::''ρETM'' - результат конвертирования значения TOA reflectance из Landsat 8 в Landsat 7;&lt;br /&gt;
::''ρOLI'' - вычисленное для Landsat8 значение TOA reflectance;&lt;br /&gt;
::''c0'' - смещение значения отражённой радиации между датчиками OLI и ETM+;&lt;br /&gt;
::''c1'' - усиление значения отражённой радиации между датчиками OLI и ETM+.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Значения c0 и с1 формулы (11) были сведены автором в корректировочные таблицы, что позволяет применять их без повторения вычислений представленных в статье Neil Flood, 2014 [9].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Программная реализация нормализации геоснимков для трёх типов спутников Landsat: 5,7,8'''==&lt;br /&gt;
&lt;br /&gt;
Все вычисления производились с использованием языка программирования python. Для этого была написана собственная программа нормализации геоданных с использованием интерфейса GDAL (библиотеки для работы с растровыми географическими форматами), тесно связанного с расширением numpy, добавляющим в язык программирования поддержку больших многомерных массивов и матриц, а также систему низкоуровневых математических функций для операций с этими массивами. Программа состоит из следующих структурных элементов:&lt;br /&gt;
&lt;br /&gt;
#Класса преобразования растра в массив.&lt;br /&gt;
#Класса преобразования вычисленного массива в растр.&lt;br /&gt;
#Класса сбора данных коррекции при помощи парсера _MTL.txt файла и данных выгрузки расстояний от земли до солнца [7].&lt;br /&gt;
#Выполняемого скрипта самих математических вычислений растров для проведения процесса нормализации.&lt;br /&gt;
&lt;br /&gt;
Исходные коды программы доступны для загрузки по адресу: https://github.com/oldbay/raster_tools, кроме того исходные GEOTIFF и нормализованные спектральные растры доступны по адресу: https://github.com/oldbay/paper_examples&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=='''Список использованных источников'''==&lt;br /&gt;
&lt;br /&gt;
# Официальный сайт Геологической Службы Соединённых Штатов - USGS [Электронный ресурс]. Режим доступа: http://www.usgs.gov.&lt;br /&gt;
# Интреактивный WEB-интерфейс получения данных дистанционного зондирования с ресурса Геологической Службы Соединённых Штатов [Электронный ресурс]. Режим доступа: http://glovis.usgs.gov.&lt;br /&gt;
# Thome K.J., Biggar S.F., Gellman D.L., Slater P.N. (1994) - Absolute-radiometric calibration of Landsat-5 Thematic Mapper and the proposed calibration of the Advanced Spaceborne Thermal Emission and Reflection Radiometer. Paper presented at the Geoscience and Remote Sensing Symposium, 1994. IGARSS’94. Surface and Atmospheric Remote Sensing: Technologies, Data Analysis and Interpretation.&lt;br /&gt;
# Lu D., Mausel P., Brondizio E., Moran E. (2002) - Assessment of atmospheric correction methods for Landsat TM data applicable to Amazon basin LBA research. International Journal of Remote Sensing, 23 (13): 2651-2671.&lt;br /&gt;
# Chavez, P. S. (1996). Image-based atmospheric correction—revisited and improved. Photogrammetric Engineering and Remote Sensing, 62(9), 1025 – 1036.&lt;br /&gt;
# Sobrino J. A., Jiménez-Muñoz J.C., Paolini L. (2004) - Land surface temperature retrieval from LANDSAT TM 5. Remote sensing of Environment, 90 (4): 434-440.&lt;br /&gt;
# «HORIZONS Web-Interface» [Electronic resource]. Access mode: http://ssd.jpl.nasa.gov/horizons.cgi.&lt;br /&gt;
# «Calculates top-of-atmosphere radiance or reflectance and temperature for Landsat MSS/TM/ETM+/OLI» [Electronic resource]. Access mode: http://grass.osgeo.org/grass65/manuals/i.landsat.toar.html.&lt;br /&gt;
# Neil Flood (2014) Continuity of Reflectance Data between Landsat-7 ETM+ and Landsat-8 OLI, for Both Top-of-Atmosphere and Surface Reflectance: A Study in the Australian Landscape. Remote Sens. 2014, 6, 7952-7970&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%90%D1%82%D0%BC%D0%BE%D1%81%D1%84%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D0%BA%D0%BE%D1%80%D1%80%D0%B5%D0%BA%D1%86%D0%B8%D1%8F_%D0%BF%D0%BE_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%83_DOS&amp;diff=22240</id>
		<title>Атмосферная коррекция по методу DOS</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%90%D1%82%D0%BC%D0%BE%D1%81%D1%84%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D0%BA%D0%BE%D1%80%D1%80%D0%B5%D0%BA%D1%86%D0%B8%D1%8F_%D0%BF%D0%BE_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%83_DOS&amp;diff=22240"/>
		<updated>2015-07-21T05:49:37Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
==&amp;lt;b&amp;gt;Анотация&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Недавно была защищена магистерская диссертация по ГИС тематике, решил выдержки из данной работы опубликовать в виде цикла статей. В первой статье рассмотрим атмосферную коррекцию по методу DOS (Dark Object Subtraction). В конце статьи представлен готовый программный инструментарий для выполения атмосферной коррекции.&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Подготовка геоданных&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Среди источников геоданных использовались данные USGS (Геологической Службы Соединённых Штатов) [1] доступных для свободного скачивания [2]. Данные с этих ресурсов представлены в формате GeoTIFF в виде непрерывных наборов сцен для различных районов мира. Представленные на ресурсах геоданные соответствуют уровню обработки LG1: «сырые геоданные» не конвертированные в значения излучения на сенсоре. Для самостоятельного проведения конвертации и атмосферной коррекции - доступны файлы настройки спутниковых сенсоров с набором ряда параметров: минимумы и максимумы пиксельной яркости на изображении; минимумы и максимумы излучения на датчиках; минимумы и максимумы отражения излучения от поверхности земли (Landsat 8) и многое другое. Кроме данных настройки спутниковых датчиков в архиве присутствуют несколько файлов в формате GeoTIFF, распределённых по номерам каналов, количество и состав которых для разных спутников (Landsat 5,7,8) различный (Таблица 1).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Таблица 1 — Спутники и используемые в работе каналы&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 |-&lt;br /&gt;
 !Спутник и датчик !! Номер канала (band) !! Название спектра !! Длинны волн (нм)&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Landsat 5 TM&lt;br /&gt;
 |1 || Blue - Синий || 450–520&lt;br /&gt;
 |-&lt;br /&gt;
 |2 || Green - Зелёный || 520–600&lt;br /&gt;
 |-&lt;br /&gt;
 |3 || Red - Красный || 630–690&lt;br /&gt;
 |-&lt;br /&gt;
 |4 || NIR — Ближний ИК || 760–900&lt;br /&gt;
 |-&lt;br /&gt;
 |5 || SWIR1 — Средний ИК 1 || 1550–1750&lt;br /&gt;
 |-&lt;br /&gt;
 |7 || SWIR2 — Средний ИК 2 || 2080–2350&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Landsat 7 ETM+&lt;br /&gt;
 |1 || Blue - Синий || 450–520&lt;br /&gt;
 |-&lt;br /&gt;
 |2 || Green - Зелёный || 520–600&lt;br /&gt;
 |-&lt;br /&gt;
 |3 || Red - Красный || 630–690&lt;br /&gt;
 |-&lt;br /&gt;
 |4 || NIR — Ближний ИК || 770–900&lt;br /&gt;
 |-&lt;br /&gt;
 |5 || SWIR1 — Средний ИК 1 || 1550–1750&lt;br /&gt;
 |-&lt;br /&gt;
 |7 || SWIR2 — Средний ИК 2 || 2080–2350&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Lansat 8 Oli&lt;br /&gt;
 |2 || Blue - Синий || 450—515&lt;br /&gt;
 |-&lt;br /&gt;
 |3 || Green - Зелёный || 525—600&lt;br /&gt;
 |-&lt;br /&gt;
 |4 || Red - Красный || 630—680&lt;br /&gt;
 |-&lt;br /&gt;
 |5 || NIR — Ближний ИК || 845—885&lt;br /&gt;
 |-&lt;br /&gt;
 |6 || SWIR1 — Средний ИК 1 || 1560—1660&lt;br /&gt;
 |-&lt;br /&gt;
 |7 || SWIR2 — Средний ИК 2 || 2100—2300&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Как видно из таблицы, шесть наиболее используемых «спектров» находятся у разных спутников в сходном диапазоне частот. Поэтому, для удобства использования терминологии, вместо указания спутниковых каналов в дальнейшем будем использовать самоназвание спектров: BLUE - синий, GREEN - зелёный, RED - красный, NIR - ближний инфракрасный, SWIR1 - средний инфракрасный 1, SWIR2 - средний инфракрасный 2 - вне зависимости от спутника и применять к ним одинаковый набор вычислений.&lt;br /&gt;
&lt;br /&gt;
Как уже упоминалось, геоданные по всем каналам предоставлены уровнем обработки LG1 - в сыром виде, это означает что предоставленные канальные GeoTIFF не более чем спозиционированные на местности яркостные «фотографии», которые, в таком виде, не могут быть использованы для ГИС исследований. Поэтому данные уровня обработки LG1 необходимо нормализовать - то есть провести конвертацию значений яркости в показатели излучения на сенсоре и атмосферную коррекцию.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Конвертация значений яркости исходного GeoTIFF в показатели излучения на сенсоре&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Теоретические основы процесса конвертирования подробно описаны в статье [http://gis-lab.info/qa/dn2radiance.html 'Конвертация данных TM, ETM+ в показатели излучения на сенсоре'], потому коснёмся только практической реализации процесса.&lt;br /&gt;
&lt;br /&gt;
Конвертирование является первым этапом нормализации сырых геоданных и представляет из себя математическую операцию перевода значения яркости пикселей геоснимка в значения радиации поступившей на датчики спутника. Для такого перевода в комплекте данных Landsat присутствует файл коррекции _MTL.txt, предельные значения из которого и используются на этом этапе обработки геоснимка.&lt;br /&gt;
&lt;br /&gt;
Для проведения работы использовалась стандартная, описанная в документации NASA, формула (1) перевода яркости в значение top of atmosphere radiance (TOA radiance) &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:F_01.png]]    (1)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλ'' - спектральная радиация, пришедшая на сенсор спутника;&lt;br /&gt;
::''DNcal'' - значения яркости пикселя сырого геоснимка;&lt;br /&gt;
::''Qcalmin'' - минимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''Qcalmax'' - максимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''LMINλ'' - минимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка;&lt;br /&gt;
::''LMAXλ'' - максимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Кроме того для вычисления TOA radiance можно использовать упрощенную формулу (2) Thome et al., 1994 [3], Lu et al 2002 [4].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''Lλ = DNcal × Gainλ + Baisλ''    (2)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλ'' - спектральная радиация, пришедшая на сенсор спутника;&lt;br /&gt;
::''DNcal'' - значения яркости пикселя сырого геоснимка;&lt;br /&gt;
::''Gainλ'' - усиление значения радиации относительно яркости исходного геоснимка;&lt;br /&gt;
::''Baisλ'' - смещение значения радиации относительно яркости исходного геоснимка.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
После обсчёта каждого пикселя геоснимка с использованием данной формулы, получаем матрицу значений c плавающей точкой - нормализованных геоданных. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Атмосферная коррекция&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Следующим этапом нормализации геоданных является уменьшение влияния атмосферы на снимок и перевод значений радиации, дошедшей до сенсоров спутника (TOA radiance), в значения реально отражённого от земли спектрального излучения солнечного света.&lt;br /&gt;
&lt;br /&gt;
Материалы данного и последующих разделов, в некоторой степени, перекликаются со статьёй [http://gis-lab.info/qa/atcor.html &amp;quot;Атмосферная коррекция данных Landsat/ETM+ (COST метод)&amp;quot;], но в отличии от неё ориентированы на пакетную обработку ДДЗ из нескольких источников.&lt;br /&gt;
&lt;br /&gt;
Влияние атмосферы на геоснимок проявляется в целом ряде факторов: угол падения и отражения солнечных лучей, прозрачность атмосферы, газовый фактор и дымка (Рисунок 1).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Файл:Dos_img_1.jpg]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Рисунок 1 — Факторы, влияющие на попадание отраженной солнечной радиации на сенсоры спутника&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Для дальнейших исследований необходимо провести оптическую коррекцию (нормализацию) данных геоснимка методом Dark Object Subtraction (DOS), впервые представленным Chavez (1996) [5]. Суть метода состоит в нахождении яркости однопроцентно тёмного объекта геоснимка с последующей коррекцией минимума значений каждого пикселя изображения, относительно спектральной яркости найденного объекта.&lt;br /&gt;
&lt;br /&gt;
Есть два основных способа поиска 1% темного объекта (Dark Object) для метода DOS:&lt;br /&gt;
# эмпирический метод - подразумевает поиск значений в ручном режиме, например, с использованием инструмента гистограмма в QGIS, где изменяя нижний порог яркости гистограммы постепенно находим примерное значение яркости искомого тёмного объекта;&lt;br /&gt;
#вычислительный метод подразумевает, что суммарная яркость (от 0 до n) однопроцентно тёмного объекта будет соответствовать 0.01% от суммарной яркости всех пикселей геоснимка Sobrino et al., 2004 [6].&lt;br /&gt;
В данной работе успешно применяли метод (2), хорошо показавший себя при обработке большого количества геоснимков исследуемого района.&lt;br /&gt;
&lt;br /&gt;
После определения яркости Dark Object (в дальнейших вычислениях будем обозначать его как DNmin), производим атмосферную коррекцию по методу DOS в несколько этапов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
====1.Вычисляем значение радиации, соответствующее значению яркости 1% темного объекта (расчёт производится по аналогии с TOA radiance), по формуле (3).====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_03.png]]    (3)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта;&lt;br /&gt;
::''DNmin'' - значения яркости пикселя 1% тёмного объекта;&lt;br /&gt;
::''Qcalmin'' - минимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''Qcalmax'' - максимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''LMINλ'' - минимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка;&lt;br /&gt;
::''LMAXλ'' - максимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка.    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Или с использованием упрощённой формы (4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''Lλmin = DNmin × Gainλ + Baisλ'' (4)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта;&lt;br /&gt;
::''DNmin'' - значения яркости пикселя 1% тёмного объекта;&lt;br /&gt;
::''Gainλ'' - усиление значения радиации относительно яркости 1% тёмного объекта;&lt;br /&gt;
::''Baisλ'' - смещение значения радиации относительно яркости 1% тёмного объекта.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====2.Рассчитываем коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта по формуле (5).====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_05.png]] (5)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' - коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта;&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''E&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;'' - коэффициент солнечного внеатмосферного спектрального излучения (явно представлен как табличные данные и учитывается при калибровке датчиков Landsat 5 и 7 , для Landsat 8 дополнительно вычисляется);&lt;br /&gt;
::''θ'' - зенитное расстояние для солнца в радианах;&lt;br /&gt;
::''T&amp;lt;sub&amp;gt;Z&amp;lt;/sub&amp;gt;'' - мера прохождения излучения от солнца до земли, в методе DOS2, принимается равным cosθ.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
====3.Вычисляем значение атмосферной дымки (hazing) по формуле (6).====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''Lλhaze = Lλmin - L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' (6)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλhaze'' - значение атмосферной дымки (hazing);&lt;br /&gt;
::''L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' - коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта;&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
====4.Рассчитываем атмосферно скорректированные значения отражённой солнечной радиации по формуле (7).====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_07.png]] (7)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''ρλ'' - атмоферно скорректированные значения отражённой солнечной радиации;&lt;br /&gt;
::''Lλ'' - значения радиации пришедшей на сенсор спутника;&lt;br /&gt;
::''Lλhaze'' - значение атмосферной дымки (hazing);&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''E&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;'' - коэффициент солнечного внеатмосферного спектрального излучения (явно представлен как табличные данные и учитывается при калибровке датчиков Landsat 5 и 7 , для Landsat 8 дополнительно вычисляется);&lt;br /&gt;
::''θ'' - зенитное расстояние для солнца в радианах;&lt;br /&gt;
::''T&amp;lt;sub&amp;gt;Z&amp;lt;/sub&amp;gt;'' - мера прохождения излучения от солнца до земли, в методе DOS2, принимается равным cosθ.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
==&amp;lt;b&amp;gt;Особенности работы с растрами спутника Landsat 8&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Если часть сцен сняты спутником Landsat 8 датчик Oli, необходимость их сравнения со сценами спутников lansat5 (датчик TM) и landsat8 (датчик ETM+). В данном контексте известна проблема применения стандартных методов атмосферной коррекции для нового спутника: дело в том, что калибровка датчиков Oli Landsat 8 производится без учёта значений коэффициента солнечного внеатмосферного спектрального излучения Eo (Sobrino et al., 2004) [6] или ,в других источниках, Esun. Вместо использования данного коэффициента, в файл корректировки _MTL.txt, были добавлены некоторые новые спектральные параметры: REFLECTANCE_MULT_BAND - усиление значения отражения и REFLECTANCE_ADD_BAND - смещение значения отражения для каждого из спектральных датчиков. В результате, по задумке авторов изменений, расчет TOA reflectance для Landsat 8 должен производится по формуле (8).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''ρλ' = MρQcal+ Aρ'' (8)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где: &lt;br /&gt;
::''ρλ''' - значение верхнеатмосфеного планетарного отражения радиации (TOA reflectance), без учёта коррекции по углу падения и отражения солнечных лучей;&lt;br /&gt;
::''Mρ'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_MULT_BAND_x, где x это номер канала) - усиление значения отражения;&lt;br /&gt;
::''Aρ'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_ADD_BAND_x,где x это номер канала) - смещение значения отражения;&lt;br /&gt;
::''Qcal'' - значения яркости пикселя сырого геоснимка (DN).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
А коррекция TOA reflectance с учётом угла падения и отражения солнечных лучей вычисляется по формуле (9).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_09.png]] (9)                               &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где: &lt;br /&gt;
::''ρλ'' - значение верхнеатмосфеного планетарного отражения радиации (TOA reflectance), c учётом коррекции по углу падения и отражения солнечных лучей;&lt;br /&gt;
::''θSE'' - высота солнца над горизонтом. Доступна в файле _MTL.txt в параметре (SUN_ELEVATION);&lt;br /&gt;
::''θSZ'' - зенитное расстояние; θSZ = 90° - θSE.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Сообщество разработчиков свободной GIS GRASS указывает на одинаковые значения REFLECTANCE_MULT_BAND и REFLECTANCE_ADD_BAND для всех каналов снимка [8], что не может быть в реальности. Данная группа разработчиков в своём модуле нормализации и атмосферной коррекции i.landsat.toar применяет к георастрам, снятым при помощи датчиков Oli Landsat 8, те же математические методы, что для TM Landsat 5 и ETM+ Landsat 7, а недостающий коэффициент Eo (Esun) рассчитывает по формуле (10).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_10.png]] (10)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Esun'' - (E0) вычисленный коэффициент солнечного внеатмосферного спектрального излучения;&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''RADIANCE_MAXIMUM'' - каналоспецифичный мультипликативный расчётный фактор для (RADIANCE_MAXIMUM_x, где x это номер канала) - максимально возможное значение поступающей на сенсор радиации;&lt;br /&gt;
::''REFLECTANCE_MAXIMUM'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_MAXIMUM_x, где x это номер канала) - максимальное значение радиации, отражённой от поверхности земли.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Ещё одной особенностью Landsat8 стало уменьшение чувствительности каналов RED, NIR и SWIR1 относительно Landsat 7 и 5 , что приводит к изменению значений, вычисляемых с использованием данных спектров, индексов.&lt;br /&gt;
&lt;br /&gt;
Данную проблему пытался решить Neil Flood, 2014 [9] введением дополнительных, рассчитанных им эмпирическим путём, коэффициентов для каждого канала геоснимка. В результате, коррекция значений TOA reflectance Landsat8 в значения для того же региона и тех же спектров Landsat7, приобретает вид формулы (11).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''ρETM+ = c0 + c1 × ρOLI'' (11)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''ρETM'' - результат конвертирования значения TOA reflectance из Landsat 8 в Landsat 7;&lt;br /&gt;
::''ρOLI'' - вычисленное для Landsat8 значение TOA reflectance;&lt;br /&gt;
::''c0'' - смещение значения отражённой радиации между датчиками OLI и ETM+;&lt;br /&gt;
::''c1'' - усиление значения отражённой радиации между датчиками OLI и ETM+.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Значения c0 и с1 формулы (11) были сведены автором в корректировочные таблицы, что позволяет применять их без повторения вычислений представленных в статье Neil Flood, 2014 [9].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Программная реализация нормализации геоснимков для трёх типов спутников Landsat: 5,7,8&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Все вычисления производились с использованием языка программирования python. Для этого была написана собственная программа нормализации геоданных с использованием интерфейса GDAL (библиотеки для работы с растровыми географическими форматами), тесно связанного с расширением numpy, добавляющим в язык программирования поддержку больших многомерных массивов и матриц, а также систему низкоуровневых математических функций для операций с этими массивами. Программа состоит из следующих структурных элементов:&lt;br /&gt;
&lt;br /&gt;
#Класса преобразования растра в массив.&lt;br /&gt;
#Класса преобразования вычисленного массива в растр.&lt;br /&gt;
#Класса сбора данных коррекции при помощи парсера _MTL.txt файла и данных выгрузки расстояний от земли до солнца [7].&lt;br /&gt;
#Выполняемого скрипта самих математических вычислений растров для проведения процесса нормализации.&lt;br /&gt;
&lt;br /&gt;
Исходные коды программы доступны для загрузки по адресу: https://github.com/oldbay/raster_tools, кроме того исходные GEOTIFF и нормализованные спектральные растры доступны по адресу: https://github.com/oldbay/paper_examples&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
==&amp;lt;b&amp;gt;Список использованных источников&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
# Официальный сайт Геологической Службы Соединённых Штатов - USGS [Электронный ресурс]. Режим доступа: http://www.usgs.gov.&lt;br /&gt;
# Интреактивный WEB-интерфейс получения данных дистанционного зондирования с ресурса Геологической Службы Соединённых Штатов [Электронный ресурс]. Режим доступа: http://glovis.usgs.gov.&lt;br /&gt;
# Thome K.J., Biggar S.F., Gellman D.L., Slater P.N. (1994) - Absolute-radiometric calibration of Landsat-5 Thematic Mapper and the proposed calibration of the Advanced Spaceborne Thermal Emission and Reflection Radiometer. Paper presented at the Geoscience and Remote Sensing Symposium, 1994. IGARSS’94. Surface and Atmospheric Remote Sensing: Technologies, Data Analysis and Interpretation.&lt;br /&gt;
# Lu D., Mausel P., Brondizio E., Moran E. (2002) - Assessment of atmospheric correction methods for Landsat TM data applicable to Amazon basin LBA research. International Journal of Remote Sensing, 23 (13): 2651-2671.&lt;br /&gt;
# Chavez, P. S. (1996). Image-based atmospheric correction—revisited and improved. Photogrammetric Engineering and Remote Sensing, 62(9), 1025 – 1036.&lt;br /&gt;
# Sobrino J. A., Jiménez-Muñoz J.C., Paolini L. (2004) - Land surface temperature retrieval from LANDSAT TM 5. Remote sensing of Environment, 90 (4): 434-440.&lt;br /&gt;
# «HORIZONS Web-Interface» [Electronic resource]. Access mode: http://ssd.jpl.nasa.gov/horizons.cgi.&lt;br /&gt;
# «Calculates top-of-atmosphere radiance or reflectance and temperature for Landsat MSS/TM/ETM+/OLI» [Electronic resource]. Access mode: http://grass.osgeo.org/grass65/manuals/i.landsat.toar.html.&lt;br /&gt;
# Neil Flood (2014) Continuity of Reflectance Data between Landsat-7 ETM+ and Landsat-8 OLI, for Both Top-of-Atmosphere and Surface Reflectance: A Study in the Australian Landscape. Remote Sens. 2014, 6, 7952-7970&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%90%D1%82%D0%BC%D0%BE%D1%81%D1%84%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D0%BA%D0%BE%D1%80%D1%80%D0%B5%D0%BA%D1%86%D0%B8%D1%8F_%D0%BF%D0%BE_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%83_DOS&amp;diff=22217</id>
		<title>Атмосферная коррекция по методу DOS</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%90%D1%82%D0%BC%D0%BE%D1%81%D1%84%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D0%BA%D0%BE%D1%80%D1%80%D0%B5%D0%BA%D1%86%D0%B8%D1%8F_%D0%BF%D0%BE_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%83_DOS&amp;diff=22217"/>
		<updated>2015-07-18T19:25:09Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* 1.Вычисляем значение радиации, соответствующее значению яркости 1% темного объекта (расчёт производится по аналогии с TOA radiance), по форм…&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
==&amp;lt;b&amp;gt;Анотация&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Недавно была защищена магистерская диссертация по ГИС тематике, решил выдержки из данной работы опубликовать в виде цикла статей. В первой статье рассмотрим атмосферную коррекцию по методу DOS (Dark Object Subtraction). В конце статьи представлен готовый программный инструментарий для выполения атмосферной коррекции.&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Подготовка геоданных&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Среди источников геоданных использовались данные USGS (Геологической Службы Соединённых Штатов) [1] доступных для свободного скачивания [2]. Данные с этих ресурсов представлены в формате GeoTIFF в виде непрерывных наборов сцен для различных районов мира. Представленные на ресурсах геоданные соответствуют уровню обработки LG1: «сырые геоданные» не конвертированные в значения излучения на сенсоре. Для самостоятельного проведения конвертации и атмосферной коррекции - доступны файлы настройки спутниковых сенсоров с набором ряда параметров: минимумы и максимумы пиксельной яркости на изображении; минимумы и максимумы излучения на датчиках; минимумы и максимумы отражения излучения от поверхности земли (Landsat 8) и многое другое. Кроме данных настройки спутниковых датчиков в архиве присутствуют несколько файлов в формате GeoTIFF, распределённых по номерам каналов, количество и состав которых для разных спутников (Landsat 5,7,8) различный (Таблица 1).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Таблица 1 — Спутники и используемые в работе каналы&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 !Спутник и датчик&lt;br /&gt;
 !Порядковый номер канала (band)&lt;br /&gt;
 !Название спектра&lt;br /&gt;
 !Длинны волн (нм)&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Landsat 5 TM&lt;br /&gt;
 |1&lt;br /&gt;
 |Blue - Синий&lt;br /&gt;
 |450–520&lt;br /&gt;
 |-&lt;br /&gt;
 |2&lt;br /&gt;
 |Green - Зелёный&lt;br /&gt;
 |520–600&lt;br /&gt;
 |-&lt;br /&gt;
 |3&lt;br /&gt;
 |Red - Красный&lt;br /&gt;
 |630–690&lt;br /&gt;
 |-&lt;br /&gt;
 |4&lt;br /&gt;
 |NIR — Ближний ИК&lt;br /&gt;
 |760–900&lt;br /&gt;
 |-&lt;br /&gt;
 |5&lt;br /&gt;
 |SWIR1 — Средний ИК 1&lt;br /&gt;
 |1550–1750&lt;br /&gt;
 |-&lt;br /&gt;
 |7&lt;br /&gt;
 |SWIR2 — Средний ИК 2&lt;br /&gt;
 |2080–2350&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Landsat 7 ETM+&lt;br /&gt;
 |1&lt;br /&gt;
 |Blue - Синий&lt;br /&gt;
 |450–520&lt;br /&gt;
 |-&lt;br /&gt;
 |2&lt;br /&gt;
 |Green - Зелёный&lt;br /&gt;
 |520–600&lt;br /&gt;
 |-&lt;br /&gt;
 |3&lt;br /&gt;
 |Red - Красный&lt;br /&gt;
 |630–690&lt;br /&gt;
 |-&lt;br /&gt;
 |4&lt;br /&gt;
 |NIR — Ближний ИК&lt;br /&gt;
 |770–900&lt;br /&gt;
 |-&lt;br /&gt;
 |5&lt;br /&gt;
 |SWIR1 — Средний ИК 1&lt;br /&gt;
 |1550–1750&lt;br /&gt;
 |-&lt;br /&gt;
 |7&lt;br /&gt;
 |SWIR2 — Средний ИК 2&lt;br /&gt;
 |2080–2350&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Lansat 8 Oli&lt;br /&gt;
 |2&lt;br /&gt;
 |Blue - Синий&lt;br /&gt;
 |450—515&lt;br /&gt;
 |-&lt;br /&gt;
 |3&lt;br /&gt;
 |Green - Зелёный&lt;br /&gt;
 |525—600&lt;br /&gt;
 |-&lt;br /&gt;
 |4&lt;br /&gt;
 |Red - Красный&lt;br /&gt;
 |630—680&lt;br /&gt;
 |-&lt;br /&gt;
 |5&lt;br /&gt;
 |NIR — Ближний ИК&lt;br /&gt;
 |845—885&lt;br /&gt;
 |-&lt;br /&gt;
 |6&lt;br /&gt;
 |SWIR1 — Средний ИК 1&lt;br /&gt;
 |1560—1660&lt;br /&gt;
 |-&lt;br /&gt;
 |7&lt;br /&gt;
 |SWIR2 — Средний ИК 2&lt;br /&gt;
 |2100—2300&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Как видно из таблицы, шесть наиболее используемых «спектров» находятся у разных спутников в сходном диапазоне частот. Поэтому, для удобства использования терминологии, вместо указания спутниковых каналов в дальнейшем будем использовать самоназвание спектров: BLUE - синий, GREEN - зелёный, RED - красный, NIR - ближний инфракрасный, SWIR1 - средний инфракрасный 1, SWIR2 - средний инфракрасный 2 - вне зависимости от спутника и применять к ним одинаковый набор вычислений.&lt;br /&gt;
&lt;br /&gt;
Как уже упоминалось, геоданные по всем каналам предоставлены уровнем обработки LG1 - в сыром виде, это означает что предоставленные канальные GeoTIFF не более чем спозиционированные на местности яркостные «фотографии», которые, в таком виде, не могут быть использованы для ГИС исследований. Поэтому данные уровня обработки LG1 необходимо нормализовать - то есть провести конвертацию значений яркости в показатели излучения на сенсоре и атмосферную коррекцию.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Конвертация значений яркости исходного GeoTIFF в показатели излучения на сенсоре&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Теоретические основы процесса конвертирования подробно описаны в статье [http://gis-lab.info/qa/dn2radiance.html 'Конвертация данных TM, ETM+ в показатели излучения на сенсоре'], потому коснёмся только практической реализации процесса.&lt;br /&gt;
&lt;br /&gt;
Конвертирование является первым этапом нормализации сырых геоданных и представляет из себя математическую операцию перевода значения яркости пикселей геоснимка в значения радиации поступившей на датчики спутника. Для такого перевода в комплекте данных Landsat присутствует файл коррекции _MTL.txt, предельные значения из которого и используются на этом этапе обработки геоснимка.&lt;br /&gt;
&lt;br /&gt;
Для проведения работы использовалась стандартная, описанная в документации NASA, формула (1) перевода яркости в значение top of atmosphere radiance (TOA radiance) &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:F_01.png]]    (1)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλ'' - спектральная радиация, пришедшая на сенсор спутника;&lt;br /&gt;
::''DNcal'' - значения яркости пикселя сырого геоснимка;&lt;br /&gt;
::''Qcalmin'' - минимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''Qcalmax'' - максимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''LMINλ'' - минимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка;&lt;br /&gt;
::''LMAXλ'' - максимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Кроме того для вычисления TOA radiance можно использовать упрощенную формулу (2) Thome et al., 1994 [3], Lu et al 2002 [4].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''Lλ = DNcal × Gainλ + Baisλ''    (2)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλ'' - спектральная радиация, пришедшая на сенсор спутника;&lt;br /&gt;
::''DNcal'' - значения яркости пикселя сырого геоснимка;&lt;br /&gt;
::''Gainλ'' - усиление значения радиации относительно яркости исходного геоснимка;&lt;br /&gt;
::''Baisλ'' - смещение значения радиации относительно яркости исходного геоснимка.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
После обсчёта каждого пикселя геоснимка с использованием данной формулы, получаем матрицу значений c плавающей точкой - нормализованных геоданных. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Атмосферная коррекция&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Следующим этапом нормализации геоданных является уменьшение влияния атмосферы на снимок и перевод значений радиации, дошедшей до сенсоров спутника (TOA radiance), в значения реально отражённого от земли спектрального излучения солнечного света.&lt;br /&gt;
&lt;br /&gt;
Материалы данного и последующих разделов, в некоторой степени, перекликаются со статьёй [http://gis-lab.info/qa/atcor.html &amp;quot;Атмосферная коррекция данных Landsat/ETM+ (COST метод)&amp;quot;], но в отличии от неё ориентированы на пакетную обработку ДДЗ из нескольких источников.&lt;br /&gt;
&lt;br /&gt;
Влияние атмосферы на геоснимок проявляется в целом ряде факторов: угол падения и отражения солнечных лучей, прозрачность атмосферы, газовый фактор и дымка (Рисунок 1).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Файл:Dos_img_1.jpg]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Рисунок 1 — Факторы, влияющие на попадание отраженной солнечной радиации на сенсоры спутника&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Для дальнейших исследований необходимо провести оптическую коррекцию (нормализацию) данных геоснимка методом Dark Object Subtraction (DOS), впервые представленным Chavez (1996) [5]. Суть метода состоит в нахождении яркости однопроцентно тёмного объекта геоснимка с последующей коррекцией минимума значений каждого пикселя изображения, относительно спектральной яркости найденного объекта.&lt;br /&gt;
&lt;br /&gt;
Есть два основных способа поиска 1% темного объекта (Dark Object) для метода DOS:&lt;br /&gt;
# эмпирический метод - подразумевает поиск значений в ручном режиме, например, с использованием инструмента гистограмма в QGIS, где изменяя нижний порог яркости гистограммы постепенно находим примерное значение яркости искомого тёмного объекта;&lt;br /&gt;
#вычислительный метод подразумевает, что суммарная яркость (от 0 до n) однопроцентно тёмного объекта будет соответствовать 0.01% от суммарной яркости всех пикселей геоснимка Sobrino et al., 2004 [6].&lt;br /&gt;
В данной работе успешно применяли метод (2), хорошо показавший себя при обработке большого количества геоснимков исследуемого района.&lt;br /&gt;
&lt;br /&gt;
После определения яркости Dark Object (в дальнейших вычислениях будем обозначать его как DNmin), производим атмосферную коррекцию по методу DOS в несколько этапов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
====1.Вычисляем значение радиации, соответствующее значению яркости 1% темного объекта (расчёт производится по аналогии с TOA radiance), по формуле (3).====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_03.png]]    (3)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта;&lt;br /&gt;
::''DNmin'' - значения яркости пикселя 1% тёмного объекта;&lt;br /&gt;
::''Qcalmin'' - минимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''Qcalmax'' - максимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''LMINλ'' - минимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка;&lt;br /&gt;
::''LMAXλ'' - максимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка.    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Или с использованием упрощённой формы (4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''Lλmin = DNmin × Gainλ + Baisλ'' (4)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта;&lt;br /&gt;
::''DNmin'' - значения яркости пикселя 1% тёмного объекта;&lt;br /&gt;
::''Gainλ'' - усиление значения радиации относительно яркости 1% тёмного объекта;&lt;br /&gt;
::''Baisλ'' - смещение значения радиации относительно яркости 1% тёмного объекта.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====2.Рассчитываем коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта по формуле (5).====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_05.png]] (5)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' - коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта;&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''E&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;'' - коэффициент солнечного внеатмосферного спектрального излучения (явно представлен как табличные данные и учитывается при калибровке датчиков Landsat 5 и 7 , для Landsat 8 дополнительно вычисляется);&lt;br /&gt;
::''θ'' - зенитное расстояние для солнца в радианах;&lt;br /&gt;
::''T&amp;lt;sub&amp;gt;Z&amp;lt;/sub&amp;gt;'' - мера прохождения излучения от солнца до земли, в методе DOS2, принимается равным cosθ.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
====3.Вычисляем значение атмосферной дымки (hazing) по формуле (6).====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''Lλhaze = Lλmin - L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' (6)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλhaze'' - значение атмосферной дымки (hazing);&lt;br /&gt;
::''L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' - коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта;&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
====4.Рассчитываем атмосферно скорректированные значения отражённой солнечной радиации по формуле (7).====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_07.png]] (7)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''ρλ'' - атмоферно скорректированные значения отражённой солнечной радиации;&lt;br /&gt;
::''Lλ'' - значения радиации пришедшей на сенсор спутника;&lt;br /&gt;
::''Lλhaze'' - значение атмосферной дымки (hazing);&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''E&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;'' - коэффициент солнечного внеатмосферного спектрального излучения (явно представлен как табличные данные и учитывается при калибровке датчиков Landsat 5 и 7 , для Landsat 8 дополнительно вычисляется);&lt;br /&gt;
::''θ'' - зенитное расстояние для солнца в радианах;&lt;br /&gt;
::''T&amp;lt;sub&amp;gt;Z&amp;lt;/sub&amp;gt;'' - мера прохождения излучения от солнца до земли, в методе DOS2, принимается равным cosθ.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
==&amp;lt;b&amp;gt;Особенности работы с растрами спутника Landsat 8&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Если часть сцен сняты спутником Landsat 8 датчик Oli, необходимость их сравнения со сценами спутников lansat5 (датчик TM) и landsat8 (датчик ETM+). В данном контексте известна проблема применения стандартных методов атмосферной коррекции для нового спутника: дело в том, что калибровка датчиков Oli Landsat 8 производится без учёта значений коэффициента солнечного внеатмосферного спектрального излучения Eo (Sobrino et al., 2004) [6] или ,в других источниках, Esun. Вместо использования данного коэффициента, в файл корректировки _MTL.txt, были добавлены некоторые новые спектральные параметры: REFLECTANCE_MULT_BAND - усиление значения отражения и REFLECTANCE_ADD_BAND - смещение значения отражения для каждого из спектральных датчиков. В результате, по задумке авторов изменений, расчет TOA reflectance для Landsat 8 должен производится по формуле (8).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''ρλ' = MρQcal+ Aρ'' (8)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где: &lt;br /&gt;
::''ρλ''' - значение верхнеатмосфеного планетарного отражения радиации (TOA reflectance), без учёта коррекции по углу падения и отражения солнечных лучей;&lt;br /&gt;
::''Mρ'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_MULT_BAND_x, где x это номер канала) - усиление значения отражения;&lt;br /&gt;
::''Aρ'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_ADD_BAND_x,где x это номер канала) - смещение значения отражения;&lt;br /&gt;
::''Qcal'' - значения яркости пикселя сырого геоснимка (DN).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
А коррекция TOA reflectance с учётом угла падения и отражения солнечных лучей вычисляется по формуле (9).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_09.png]] (9)                               &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где: &lt;br /&gt;
::''ρλ'' - значение верхнеатмосфеного планетарного отражения радиации (TOA reflectance), c учётом коррекции по углу падения и отражения солнечных лучей;&lt;br /&gt;
::''θSE'' - высота солнца над горизонтом. Доступна в файле _MTL.txt в параметре (SUN_ELEVATION);&lt;br /&gt;
::''θSZ'' - зенитное расстояние; θSZ = 90° - θSE.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Сообщество разработчиков свободной GIS GRASS указывает на одинаковые значения REFLECTANCE_MULT_BAND и REFLECTANCE_ADD_BAND для всех каналов снимка [8], что не может быть в реальности. Данная группа разработчиков в своём модуле нормализации и атмосферной коррекции i.landsat.toar применяет к георастрам, снятым при помощи датчиков Oli Landsat 8, те же математические методы, что для TM Landsat 5 и ETM+ Landsat 7, а недостающий коэффициент Eo (Esun) рассчитывает по формуле (10).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_10.png]] (10)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Esun'' - (E0) вычисленный коэффициент солнечного внеатмосферного спектрального излучения;&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''RADIANCE_MAXIMUM'' - каналоспецифичный мультипликативный расчётный фактор для (RADIANCE_MAXIMUM_x, где x это номер канала) - максимально возможное значение поступающей на сенсор радиации;&lt;br /&gt;
::''REFLECTANCE_MAXIMUM'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_MAXIMUM_x, где x это номер канала) - максимальное значение радиации, отражённой от поверхности земли.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Ещё одной особенностью Landsat8 стало уменьшение чувствительности каналов RED, NIR и SWIR1 относительно Landsat 7 и 5 , что приводит к изменению значений, вычисляемых с использованием данных спектров, индексов.&lt;br /&gt;
&lt;br /&gt;
Данную проблему пытался решить Neil Flood, 2014 [9] введением дополнительных, рассчитанных им эмпирическим путём, коэффициентов для каждого канала геоснимка. В результате, коррекция значений TOA reflectance Landsat8 в значения для того же региона и тех же спектров Landsat7, приобретает вид формулы (11).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''ρETM+ = c0 + c1 × ρOLI'' (11)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''ρETM'' - результат конвертирования значения TOA reflectance из Landsat 8 в Landsat 7;&lt;br /&gt;
::''ρOLI'' - вычисленное для Landsat8 значение TOA reflectance;&lt;br /&gt;
::''c0'' - смещение значения отражённой радиации между датчиками OLI и ETM+;&lt;br /&gt;
::''c1'' - усиление значения отражённой радиации между датчиками OLI и ETM+.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Значения c0 и с1 формулы (11) были сведены автором в корректировочные таблицы, что позволяет применять их без повторения вычислений представленных в статье Neil Flood, 2014 [9].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Программная реализация нормализации геоснимков для трёх типов спутников Landsat: 5,7,8&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Все вычисления производились с использованием языка программирования python. Для этого была написана собственная программа нормализации геоданных с использованием интерфейса GDAL (библиотеки для работы с растровыми географическими форматами), тесно связанного с расширением numpy, добавляющим в язык программирования поддержку больших многомерных массивов и матриц, а также систему низкоуровневых математических функций для операций с этими массивами. Программа состоит из следующих структурных элементов:&lt;br /&gt;
&lt;br /&gt;
#Класса преобразования растра в массив.&lt;br /&gt;
#Класса преобразования вычисленного массива в растр.&lt;br /&gt;
#Класса сбора данных коррекции при помощи парсера _MTL.txt файла и данных выгрузки расстояний от земли до солнца [7].&lt;br /&gt;
#Выполняемого скрипта самих математических вычислений растров для проведения процесса нормализации.&lt;br /&gt;
&lt;br /&gt;
Исходные коды программы доступны для загрузки по адресу: https://github.com/oldbay/raster_tools, кроме того исходные GEOTIFF и нормализованные спектральные растры доступны по адресу: https://github.com/oldbay/paper_examples&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
==&amp;lt;b&amp;gt;Список использованных источников&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
# Официальный сайт Геологической Службы Соединённых Штатов - USGS [Электронный ресурс]. Режим доступа: http://www.usgs.gov.&lt;br /&gt;
# Интреактивный WEB-интерфейс получения данных дистанционного зондирования с ресурса Геологической Службы Соединённых Штатов [Электронный ресурс]. Режим доступа: http://glovis.usgs.gov.&lt;br /&gt;
# Thome K.J., Biggar S.F., Gellman D.L., Slater P.N. (1994) - Absolute-radiometric calibration of Landsat-5 Thematic Mapper and the proposed calibration of the Advanced Spaceborne Thermal Emission and Reflection Radiometer. Paper presented at the Geoscience and Remote Sensing Symposium, 1994. IGARSS’94. Surface and Atmospheric Remote Sensing: Technologies, Data Analysis and Interpretation.&lt;br /&gt;
# Lu D., Mausel P., Brondizio E., Moran E. (2002) - Assessment of atmospheric correction methods for Landsat TM data applicable to Amazon basin LBA research. International Journal of Remote Sensing, 23 (13): 2651-2671.&lt;br /&gt;
# Chavez, P. S. (1996). Image-based atmospheric correction—revisited and improved. Photogrammetric Engineering and Remote Sensing, 62(9), 1025 – 1036.&lt;br /&gt;
# Sobrino J. A., Jiménez-Muñoz J.C., Paolini L. (2004) - Land surface temperature retrieval from LANDSAT TM 5. Remote sensing of Environment, 90 (4): 434-440.&lt;br /&gt;
# «HORIZONS Web-Interface» [Electronic resource]. Access mode: http://ssd.jpl.nasa.gov/horizons.cgi.&lt;br /&gt;
# «Calculates top-of-atmosphere radiance or reflectance and temperature for Landsat MSS/TM/ETM+/OLI» [Electronic resource]. Access mode: http://grass.osgeo.org/grass65/manuals/i.landsat.toar.html.&lt;br /&gt;
# Neil Flood (2014) Continuity of Reflectance Data between Landsat-7 ETM+ and Landsat-8 OLI, for Both Top-of-Atmosphere and Surface Reflectance: A Study in the Australian Landscape. Remote Sens. 2014, 6, 7952-7970&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%90%D1%82%D0%BC%D0%BE%D1%81%D1%84%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D0%BA%D0%BE%D1%80%D1%80%D0%B5%D0%BA%D1%86%D0%B8%D1%8F_%D0%BF%D0%BE_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%83_DOS&amp;diff=22216</id>
		<title>Атмосферная коррекция по методу DOS</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%90%D1%82%D0%BC%D0%BE%D1%81%D1%84%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D0%BA%D0%BE%D1%80%D1%80%D0%B5%D0%BA%D1%86%D0%B8%D1%8F_%D0%BF%D0%BE_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%83_DOS&amp;diff=22216"/>
		<updated>2015-07-18T19:23:42Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: /* Конвертация значений яркости исходного GeoTIFF в показатели излучения на сенсоре */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
==&amp;lt;b&amp;gt;Анотация&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Недавно была защищена магистерская диссертация по ГИС тематике, решил выдержки из данной работы опубликовать в виде цикла статей. В первой статье рассмотрим атмосферную коррекцию по методу DOS (Dark Object Subtraction). В конце статьи представлен готовый программный инструментарий для выполения атмосферной коррекции.&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Подготовка геоданных&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Среди источников геоданных использовались данные USGS (Геологической Службы Соединённых Штатов) [1] доступных для свободного скачивания [2]. Данные с этих ресурсов представлены в формате GeoTIFF в виде непрерывных наборов сцен для различных районов мира. Представленные на ресурсах геоданные соответствуют уровню обработки LG1: «сырые геоданные» не конвертированные в значения излучения на сенсоре. Для самостоятельного проведения конвертации и атмосферной коррекции - доступны файлы настройки спутниковых сенсоров с набором ряда параметров: минимумы и максимумы пиксельной яркости на изображении; минимумы и максимумы излучения на датчиках; минимумы и максимумы отражения излучения от поверхности земли (Landsat 8) и многое другое. Кроме данных настройки спутниковых датчиков в архиве присутствуют несколько файлов в формате GeoTIFF, распределённых по номерам каналов, количество и состав которых для разных спутников (Landsat 5,7,8) различный (Таблица 1).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Таблица 1 — Спутники и используемые в работе каналы&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 !Спутник и датчик&lt;br /&gt;
 !Порядковый номер канала (band)&lt;br /&gt;
 !Название спектра&lt;br /&gt;
 !Длинны волн (нм)&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Landsat 5 TM&lt;br /&gt;
 |1&lt;br /&gt;
 |Blue - Синий&lt;br /&gt;
 |450–520&lt;br /&gt;
 |-&lt;br /&gt;
 |2&lt;br /&gt;
 |Green - Зелёный&lt;br /&gt;
 |520–600&lt;br /&gt;
 |-&lt;br /&gt;
 |3&lt;br /&gt;
 |Red - Красный&lt;br /&gt;
 |630–690&lt;br /&gt;
 |-&lt;br /&gt;
 |4&lt;br /&gt;
 |NIR — Ближний ИК&lt;br /&gt;
 |760–900&lt;br /&gt;
 |-&lt;br /&gt;
 |5&lt;br /&gt;
 |SWIR1 — Средний ИК 1&lt;br /&gt;
 |1550–1750&lt;br /&gt;
 |-&lt;br /&gt;
 |7&lt;br /&gt;
 |SWIR2 — Средний ИК 2&lt;br /&gt;
 |2080–2350&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Landsat 7 ETM+&lt;br /&gt;
 |1&lt;br /&gt;
 |Blue - Синий&lt;br /&gt;
 |450–520&lt;br /&gt;
 |-&lt;br /&gt;
 |2&lt;br /&gt;
 |Green - Зелёный&lt;br /&gt;
 |520–600&lt;br /&gt;
 |-&lt;br /&gt;
 |3&lt;br /&gt;
 |Red - Красный&lt;br /&gt;
 |630–690&lt;br /&gt;
 |-&lt;br /&gt;
 |4&lt;br /&gt;
 |NIR — Ближний ИК&lt;br /&gt;
 |770–900&lt;br /&gt;
 |-&lt;br /&gt;
 |5&lt;br /&gt;
 |SWIR1 — Средний ИК 1&lt;br /&gt;
 |1550–1750&lt;br /&gt;
 |-&lt;br /&gt;
 |7&lt;br /&gt;
 |SWIR2 — Средний ИК 2&lt;br /&gt;
 |2080–2350&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Lansat 8 Oli&lt;br /&gt;
 |2&lt;br /&gt;
 |Blue - Синий&lt;br /&gt;
 |450—515&lt;br /&gt;
 |-&lt;br /&gt;
 |3&lt;br /&gt;
 |Green - Зелёный&lt;br /&gt;
 |525—600&lt;br /&gt;
 |-&lt;br /&gt;
 |4&lt;br /&gt;
 |Red - Красный&lt;br /&gt;
 |630—680&lt;br /&gt;
 |-&lt;br /&gt;
 |5&lt;br /&gt;
 |NIR — Ближний ИК&lt;br /&gt;
 |845—885&lt;br /&gt;
 |-&lt;br /&gt;
 |6&lt;br /&gt;
 |SWIR1 — Средний ИК 1&lt;br /&gt;
 |1560—1660&lt;br /&gt;
 |-&lt;br /&gt;
 |7&lt;br /&gt;
 |SWIR2 — Средний ИК 2&lt;br /&gt;
 |2100—2300&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Как видно из таблицы, шесть наиболее используемых «спектров» находятся у разных спутников в сходном диапазоне частот. Поэтому, для удобства использования терминологии, вместо указания спутниковых каналов в дальнейшем будем использовать самоназвание спектров: BLUE - синий, GREEN - зелёный, RED - красный, NIR - ближний инфракрасный, SWIR1 - средний инфракрасный 1, SWIR2 - средний инфракрасный 2 - вне зависимости от спутника и применять к ним одинаковый набор вычислений.&lt;br /&gt;
&lt;br /&gt;
Как уже упоминалось, геоданные по всем каналам предоставлены уровнем обработки LG1 - в сыром виде, это означает что предоставленные канальные GeoTIFF не более чем спозиционированные на местности яркостные «фотографии», которые, в таком виде, не могут быть использованы для ГИС исследований. Поэтому данные уровня обработки LG1 необходимо нормализовать - то есть провести конвертацию значений яркости в показатели излучения на сенсоре и атмосферную коррекцию.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Конвертация значений яркости исходного GeoTIFF в показатели излучения на сенсоре&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Теоретические основы процесса конвертирования подробно описаны в статье [http://gis-lab.info/qa/dn2radiance.html 'Конвертация данных TM, ETM+ в показатели излучения на сенсоре'], потому коснёмся только практической реализации процесса.&lt;br /&gt;
&lt;br /&gt;
Конвертирование является первым этапом нормализации сырых геоданных и представляет из себя математическую операцию перевода значения яркости пикселей геоснимка в значения радиации поступившей на датчики спутника. Для такого перевода в комплекте данных Landsat присутствует файл коррекции _MTL.txt, предельные значения из которого и используются на этом этапе обработки геоснимка.&lt;br /&gt;
&lt;br /&gt;
Для проведения работы использовалась стандартная, описанная в документации NASA, формула (1) перевода яркости в значение top of atmosphere radiance (TOA radiance) &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:F_01.png]]    (1)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλ'' - спектральная радиация, пришедшая на сенсор спутника;&lt;br /&gt;
::''DNcal'' - значения яркости пикселя сырого геоснимка;&lt;br /&gt;
::''Qcalmin'' - минимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''Qcalmax'' - максимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''LMINλ'' - минимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка;&lt;br /&gt;
::''LMAXλ'' - максимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Кроме того для вычисления TOA radiance можно использовать упрощенную формулу (2) Thome et al., 1994 [3], Lu et al 2002 [4].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''Lλ = DNcal × Gainλ + Baisλ''    (2)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλ'' - спектральная радиация, пришедшая на сенсор спутника;&lt;br /&gt;
::''DNcal'' - значения яркости пикселя сырого геоснимка;&lt;br /&gt;
::''Gainλ'' - усиление значения радиации относительно яркости исходного геоснимка;&lt;br /&gt;
::''Baisλ'' - смещение значения радиации относительно яркости исходного геоснимка.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
После обсчёта каждого пикселя геоснимка с использованием данной формулы, получаем матрицу значений c плавающей точкой - нормализованных геоданных. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Атмосферная коррекция&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Следующим этапом нормализации геоданных является уменьшение влияния атмосферы на снимок и перевод значений радиации, дошедшей до сенсоров спутника (TOA radiance), в значения реально отражённого от земли спектрального излучения солнечного света.&lt;br /&gt;
&lt;br /&gt;
Материалы данного и последующих разделов, в некоторой степени, перекликаются со статьёй [http://gis-lab.info/qa/atcor.html &amp;quot;Атмосферная коррекция данных Landsat/ETM+ (COST метод)&amp;quot;], но в отличии от неё ориентированы на пакетную обработку ДДЗ из нескольких источников.&lt;br /&gt;
&lt;br /&gt;
Влияние атмосферы на геоснимок проявляется в целом ряде факторов: угол падения и отражения солнечных лучей, прозрачность атмосферы, газовый фактор и дымка (Рисунок 1).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Файл:Dos_img_1.jpg]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Рисунок 1 — Факторы, влияющие на попадание отраженной солнечной радиации на сенсоры спутника&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Для дальнейших исследований необходимо провести оптическую коррекцию (нормализацию) данных геоснимка методом Dark Object Subtraction (DOS), впервые представленным Chavez (1996) [5]. Суть метода состоит в нахождении яркости однопроцентно тёмного объекта геоснимка с последующей коррекцией минимума значений каждого пикселя изображения, относительно спектральной яркости найденного объекта.&lt;br /&gt;
&lt;br /&gt;
Есть два основных способа поиска 1% темного объекта (Dark Object) для метода DOS:&lt;br /&gt;
# эмпирический метод - подразумевает поиск значений в ручном режиме, например, с использованием инструмента гистограмма в QGIS, где изменяя нижний порог яркости гистограммы постепенно находим примерное значение яркости искомого тёмного объекта;&lt;br /&gt;
#вычислительный метод подразумевает, что суммарная яркость (от 0 до n) однопроцентно тёмного объекта будет соответствовать 0.01% от суммарной яркости всех пикселей геоснимка Sobrino et al., 2004 [6].&lt;br /&gt;
В данной работе успешно применяли метод (2), хорошо показавший себя при обработке большого количества геоснимков исследуемого района.&lt;br /&gt;
&lt;br /&gt;
После определения яркости Dark Object (в дальнейших вычислениях будем обозначать его как DNmin), производим атмосферную коррекцию по методу DOS в несколько этапов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
====1.Вычисляем значение радиации, соответствующее значению яркости 1% темного объекта (расчёт производится по аналогии с TOA radiance), по формуле (3).====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_03.png]]    (3)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта;&lt;br /&gt;
::''DNmin'' - значения яркости пикселя 1% тёмного объекта;&lt;br /&gt;
::''Qcalmin'' - минимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''Qcalmax'' - максимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''LMINλ'' - минимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка;&lt;br /&gt;
::''LMAXλ'' - максимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка.    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Или с использованием упрощённой формы (4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''Lλmin = DNmin × Gainλ + Baisλ'' (4)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта;&lt;br /&gt;
::''DNmin'' - значения яркости пикселя 1% тёмного объекта;&lt;br /&gt;
::''Gainλ'' - радиометрическое усиление;&lt;br /&gt;
::''Baisλ'' - радиометрическое смещение.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
====2.Рассчитываем коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта по формуле (5).====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_05.png]] (5)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' - коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта;&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''E&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;'' - коэффициент солнечного внеатмосферного спектрального излучения (явно представлен как табличные данные и учитывается при калибровке датчиков Landsat 5 и 7 , для Landsat 8 дополнительно вычисляется);&lt;br /&gt;
::''θ'' - зенитное расстояние для солнца в радианах;&lt;br /&gt;
::''T&amp;lt;sub&amp;gt;Z&amp;lt;/sub&amp;gt;'' - мера прохождения излучения от солнца до земли, в методе DOS2, принимается равным cosθ.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
====3.Вычисляем значение атмосферной дымки (hazing) по формуле (6).====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''Lλhaze = Lλmin - L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' (6)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλhaze'' - значение атмосферной дымки (hazing);&lt;br /&gt;
::''L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' - коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта;&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
====4.Рассчитываем атмосферно скорректированные значения отражённой солнечной радиации по формуле (7).====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_07.png]] (7)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''ρλ'' - атмоферно скорректированные значения отражённой солнечной радиации;&lt;br /&gt;
::''Lλ'' - значения радиации пришедшей на сенсор спутника;&lt;br /&gt;
::''Lλhaze'' - значение атмосферной дымки (hazing);&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''E&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;'' - коэффициент солнечного внеатмосферного спектрального излучения (явно представлен как табличные данные и учитывается при калибровке датчиков Landsat 5 и 7 , для Landsat 8 дополнительно вычисляется);&lt;br /&gt;
::''θ'' - зенитное расстояние для солнца в радианах;&lt;br /&gt;
::''T&amp;lt;sub&amp;gt;Z&amp;lt;/sub&amp;gt;'' - мера прохождения излучения от солнца до земли, в методе DOS2, принимается равным cosθ.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
==&amp;lt;b&amp;gt;Особенности работы с растрами спутника Landsat 8&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Если часть сцен сняты спутником Landsat 8 датчик Oli, необходимость их сравнения со сценами спутников lansat5 (датчик TM) и landsat8 (датчик ETM+). В данном контексте известна проблема применения стандартных методов атмосферной коррекции для нового спутника: дело в том, что калибровка датчиков Oli Landsat 8 производится без учёта значений коэффициента солнечного внеатмосферного спектрального излучения Eo (Sobrino et al., 2004) [6] или ,в других источниках, Esun. Вместо использования данного коэффициента, в файл корректировки _MTL.txt, были добавлены некоторые новые спектральные параметры: REFLECTANCE_MULT_BAND - усиление значения отражения и REFLECTANCE_ADD_BAND - смещение значения отражения для каждого из спектральных датчиков. В результате, по задумке авторов изменений, расчет TOA reflectance для Landsat 8 должен производится по формуле (8).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''ρλ' = MρQcal+ Aρ'' (8)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где: &lt;br /&gt;
::''ρλ''' - значение верхнеатмосфеного планетарного отражения радиации (TOA reflectance), без учёта коррекции по углу падения и отражения солнечных лучей;&lt;br /&gt;
::''Mρ'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_MULT_BAND_x, где x это номер канала) - усиление значения отражения;&lt;br /&gt;
::''Aρ'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_ADD_BAND_x,где x это номер канала) - смещение значения отражения;&lt;br /&gt;
::''Qcal'' - значения яркости пикселя сырого геоснимка (DN).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
А коррекция TOA reflectance с учётом угла падения и отражения солнечных лучей вычисляется по формуле (9).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_09.png]] (9)                               &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где: &lt;br /&gt;
::''ρλ'' - значение верхнеатмосфеного планетарного отражения радиации (TOA reflectance), c учётом коррекции по углу падения и отражения солнечных лучей;&lt;br /&gt;
::''θSE'' - высота солнца над горизонтом. Доступна в файле _MTL.txt в параметре (SUN_ELEVATION);&lt;br /&gt;
::''θSZ'' - зенитное расстояние; θSZ = 90° - θSE.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Сообщество разработчиков свободной GIS GRASS указывает на одинаковые значения REFLECTANCE_MULT_BAND и REFLECTANCE_ADD_BAND для всех каналов снимка [8], что не может быть в реальности. Данная группа разработчиков в своём модуле нормализации и атмосферной коррекции i.landsat.toar применяет к георастрам, снятым при помощи датчиков Oli Landsat 8, те же математические методы, что для TM Landsat 5 и ETM+ Landsat 7, а недостающий коэффициент Eo (Esun) рассчитывает по формуле (10).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_10.png]] (10)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Esun'' - (E0) вычисленный коэффициент солнечного внеатмосферного спектрального излучения;&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''RADIANCE_MAXIMUM'' - каналоспецифичный мультипликативный расчётный фактор для (RADIANCE_MAXIMUM_x, где x это номер канала) - максимально возможное значение поступающей на сенсор радиации;&lt;br /&gt;
::''REFLECTANCE_MAXIMUM'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_MAXIMUM_x, где x это номер канала) - максимальное значение радиации, отражённой от поверхности земли.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Ещё одной особенностью Landsat8 стало уменьшение чувствительности каналов RED, NIR и SWIR1 относительно Landsat 7 и 5 , что приводит к изменению значений, вычисляемых с использованием данных спектров, индексов.&lt;br /&gt;
&lt;br /&gt;
Данную проблему пытался решить Neil Flood, 2014 [9] введением дополнительных, рассчитанных им эмпирическим путём, коэффициентов для каждого канала геоснимка. В результате, коррекция значений TOA reflectance Landsat8 в значения для того же региона и тех же спектров Landsat7, приобретает вид формулы (11).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''ρETM+ = c0 + c1 × ρOLI'' (11)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''ρETM'' - результат конвертирования значения TOA reflectance из Landsat 8 в Landsat 7;&lt;br /&gt;
::''ρOLI'' - вычисленное для Landsat8 значение TOA reflectance;&lt;br /&gt;
::''c0'' - смещение значения отражённой радиации между датчиками OLI и ETM+;&lt;br /&gt;
::''c1'' - усиление значения отражённой радиации между датчиками OLI и ETM+.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Значения c0 и с1 формулы (11) были сведены автором в корректировочные таблицы, что позволяет применять их без повторения вычислений представленных в статье Neil Flood, 2014 [9].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Программная реализация нормализации геоснимков для трёх типов спутников Landsat: 5,7,8&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Все вычисления производились с использованием языка программирования python. Для этого была написана собственная программа нормализации геоданных с использованием интерфейса GDAL (библиотеки для работы с растровыми географическими форматами), тесно связанного с расширением numpy, добавляющим в язык программирования поддержку больших многомерных массивов и матриц, а также систему низкоуровневых математических функций для операций с этими массивами. Программа состоит из следующих структурных элементов:&lt;br /&gt;
&lt;br /&gt;
#Класса преобразования растра в массив.&lt;br /&gt;
#Класса преобразования вычисленного массива в растр.&lt;br /&gt;
#Класса сбора данных коррекции при помощи парсера _MTL.txt файла и данных выгрузки расстояний от земли до солнца [7].&lt;br /&gt;
#Выполняемого скрипта самих математических вычислений растров для проведения процесса нормализации.&lt;br /&gt;
&lt;br /&gt;
Исходные коды программы доступны для загрузки по адресу: https://github.com/oldbay/raster_tools, кроме того исходные GEOTIFF и нормализованные спектральные растры доступны по адресу: https://github.com/oldbay/paper_examples&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
==&amp;lt;b&amp;gt;Список использованных источников&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
# Официальный сайт Геологической Службы Соединённых Штатов - USGS [Электронный ресурс]. Режим доступа: http://www.usgs.gov.&lt;br /&gt;
# Интреактивный WEB-интерфейс получения данных дистанционного зондирования с ресурса Геологической Службы Соединённых Штатов [Электронный ресурс]. Режим доступа: http://glovis.usgs.gov.&lt;br /&gt;
# Thome K.J., Biggar S.F., Gellman D.L., Slater P.N. (1994) - Absolute-radiometric calibration of Landsat-5 Thematic Mapper and the proposed calibration of the Advanced Spaceborne Thermal Emission and Reflection Radiometer. Paper presented at the Geoscience and Remote Sensing Symposium, 1994. IGARSS’94. Surface and Atmospheric Remote Sensing: Technologies, Data Analysis and Interpretation.&lt;br /&gt;
# Lu D., Mausel P., Brondizio E., Moran E. (2002) - Assessment of atmospheric correction methods for Landsat TM data applicable to Amazon basin LBA research. International Journal of Remote Sensing, 23 (13): 2651-2671.&lt;br /&gt;
# Chavez, P. S. (1996). Image-based atmospheric correction—revisited and improved. Photogrammetric Engineering and Remote Sensing, 62(9), 1025 – 1036.&lt;br /&gt;
# Sobrino J. A., Jiménez-Muñoz J.C., Paolini L. (2004) - Land surface temperature retrieval from LANDSAT TM 5. Remote sensing of Environment, 90 (4): 434-440.&lt;br /&gt;
# «HORIZONS Web-Interface» [Electronic resource]. Access mode: http://ssd.jpl.nasa.gov/horizons.cgi.&lt;br /&gt;
# «Calculates top-of-atmosphere radiance or reflectance and temperature for Landsat MSS/TM/ETM+/OLI» [Electronic resource]. Access mode: http://grass.osgeo.org/grass65/manuals/i.landsat.toar.html.&lt;br /&gt;
# Neil Flood (2014) Continuity of Reflectance Data between Landsat-7 ETM+ and Landsat-8 OLI, for Both Top-of-Atmosphere and Surface Reflectance: A Study in the Australian Landscape. Remote Sens. 2014, 6, 7952-7970&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%90%D1%82%D0%BC%D0%BE%D1%81%D1%84%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D0%BA%D0%BE%D1%80%D1%80%D0%B5%D0%BA%D1%86%D0%B8%D1%8F_%D0%BF%D0%BE_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%83_DOS&amp;diff=22215</id>
		<title>Атмосферная коррекция по методу DOS</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%90%D1%82%D0%BC%D0%BE%D1%81%D1%84%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D0%BA%D0%BE%D1%80%D1%80%D0%B5%D0%BA%D1%86%D0%B8%D1%8F_%D0%BF%D0%BE_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%83_DOS&amp;diff=22215"/>
		<updated>2015-07-18T19:06:41Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
==&amp;lt;b&amp;gt;Анотация&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Недавно была защищена магистерская диссертация по ГИС тематике, решил выдержки из данной работы опубликовать в виде цикла статей. В первой статье рассмотрим атмосферную коррекцию по методу DOS (Dark Object Subtraction). В конце статьи представлен готовый программный инструментарий для выполения атмосферной коррекции.&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Подготовка геоданных&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Среди источников геоданных использовались данные USGS (Геологической Службы Соединённых Штатов) [1] доступных для свободного скачивания [2]. Данные с этих ресурсов представлены в формате GeoTIFF в виде непрерывных наборов сцен для различных районов мира. Представленные на ресурсах геоданные соответствуют уровню обработки LG1: «сырые геоданные» не конвертированные в значения излучения на сенсоре. Для самостоятельного проведения конвертации и атмосферной коррекции - доступны файлы настройки спутниковых сенсоров с набором ряда параметров: минимумы и максимумы пиксельной яркости на изображении; минимумы и максимумы излучения на датчиках; минимумы и максимумы отражения излучения от поверхности земли (Landsat 8) и многое другое. Кроме данных настройки спутниковых датчиков в архиве присутствуют несколько файлов в формате GeoTIFF, распределённых по номерам каналов, количество и состав которых для разных спутников (Landsat 5,7,8) различный (Таблица 1).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Таблица 1 — Спутники и используемые в работе каналы&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 !Спутник и датчик&lt;br /&gt;
 !Порядковый номер канала (band)&lt;br /&gt;
 !Название спектра&lt;br /&gt;
 !Длинны волн (нм)&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Landsat 5 TM&lt;br /&gt;
 |1&lt;br /&gt;
 |Blue - Синий&lt;br /&gt;
 |450–520&lt;br /&gt;
 |-&lt;br /&gt;
 |2&lt;br /&gt;
 |Green - Зелёный&lt;br /&gt;
 |520–600&lt;br /&gt;
 |-&lt;br /&gt;
 |3&lt;br /&gt;
 |Red - Красный&lt;br /&gt;
 |630–690&lt;br /&gt;
 |-&lt;br /&gt;
 |4&lt;br /&gt;
 |NIR — Ближний ИК&lt;br /&gt;
 |760–900&lt;br /&gt;
 |-&lt;br /&gt;
 |5&lt;br /&gt;
 |SWIR1 — Средний ИК 1&lt;br /&gt;
 |1550–1750&lt;br /&gt;
 |-&lt;br /&gt;
 |7&lt;br /&gt;
 |SWIR2 — Средний ИК 2&lt;br /&gt;
 |2080–2350&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Landsat 7 ETM+&lt;br /&gt;
 |1&lt;br /&gt;
 |Blue - Синий&lt;br /&gt;
 |450–520&lt;br /&gt;
 |-&lt;br /&gt;
 |2&lt;br /&gt;
 |Green - Зелёный&lt;br /&gt;
 |520–600&lt;br /&gt;
 |-&lt;br /&gt;
 |3&lt;br /&gt;
 |Red - Красный&lt;br /&gt;
 |630–690&lt;br /&gt;
 |-&lt;br /&gt;
 |4&lt;br /&gt;
 |NIR — Ближний ИК&lt;br /&gt;
 |770–900&lt;br /&gt;
 |-&lt;br /&gt;
 |5&lt;br /&gt;
 |SWIR1 — Средний ИК 1&lt;br /&gt;
 |1550–1750&lt;br /&gt;
 |-&lt;br /&gt;
 |7&lt;br /&gt;
 |SWIR2 — Средний ИК 2&lt;br /&gt;
 |2080–2350&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Lansat 8 Oli&lt;br /&gt;
 |2&lt;br /&gt;
 |Blue - Синий&lt;br /&gt;
 |450—515&lt;br /&gt;
 |-&lt;br /&gt;
 |3&lt;br /&gt;
 |Green - Зелёный&lt;br /&gt;
 |525—600&lt;br /&gt;
 |-&lt;br /&gt;
 |4&lt;br /&gt;
 |Red - Красный&lt;br /&gt;
 |630—680&lt;br /&gt;
 |-&lt;br /&gt;
 |5&lt;br /&gt;
 |NIR — Ближний ИК&lt;br /&gt;
 |845—885&lt;br /&gt;
 |-&lt;br /&gt;
 |6&lt;br /&gt;
 |SWIR1 — Средний ИК 1&lt;br /&gt;
 |1560—1660&lt;br /&gt;
 |-&lt;br /&gt;
 |7&lt;br /&gt;
 |SWIR2 — Средний ИК 2&lt;br /&gt;
 |2100—2300&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Как видно из таблицы, шесть наиболее используемых «спектров» находятся у разных спутников в сходном диапазоне частот. Поэтому, для удобства использования терминологии, вместо указания спутниковых каналов в дальнейшем будем использовать самоназвание спектров: BLUE - синий, GREEN - зелёный, RED - красный, NIR - ближний инфракрасный, SWIR1 - средний инфракрасный 1, SWIR2 - средний инфракрасный 2 - вне зависимости от спутника и применять к ним одинаковый набор вычислений.&lt;br /&gt;
&lt;br /&gt;
Как уже упоминалось, геоданные по всем каналам предоставлены уровнем обработки LG1 - в сыром виде, это означает что предоставленные канальные GeoTIFF не более чем спозиционированные на местности яркостные «фотографии», которые, в таком виде, не могут быть использованы для ГИС исследований. Поэтому данные уровня обработки LG1 необходимо нормализовать - то есть провести конвертацию значений яркости в показатели излучения на сенсоре и атмосферную коррекцию.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Конвертация значений яркости исходного GeoTIFF в показатели излучения на сенсоре&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Теоретические основы процесса конвертирования подробно описаны в статье [http://gis-lab.info/qa/dn2radiance.html 'Конвертация данных TM, ETM+ в показатели излучения на сенсоре'], потому коснёмся только практической реализации процесса.&lt;br /&gt;
&lt;br /&gt;
Конвертирование является первым этапом нормализации сырых геоданных и представляет из себя математическую операцию перевода значения яркости пикселей геоснимка в значения радиации поступившей на датчики спутника. Для такого перевода в комплекте данных Landsat присутствует файл коррекции _MTL.txt, предельные значения из которого и используются на этом этапе обработки геоснимка.&lt;br /&gt;
&lt;br /&gt;
Для проведения работы использовалась стандартная, описанная в документации NASA, формула (1) перевода яркости в значение top of atmosphere radiance (TOA radiance) &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:F_01.png]]    (1)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλ'' - спектральная радиация, пришедшая на сенсор спутника;&lt;br /&gt;
::''DNcal'' - значения яркости пикселя сырого геоснимка;&lt;br /&gt;
::''Qcalmin'' - минимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''Qcalmax'' - максимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''LMINλ'' - минимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка;&lt;br /&gt;
::''LMAXλ'' - максимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Кроме того для вычисления TOA radiance можно использовать упрощенную формулу (2) Thome et al., 1994 [3], Lu et al 2002 [4].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''Lλ = DNcal × Gainλ + Baisλ''    (2)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλ'' - спектральная радиация, пришедшая на сенсор спутника;&lt;br /&gt;
::''DNcal'' - значения яркости пикселя сырого геоснимка;&lt;br /&gt;
::''Gainλ'' - радиометрическое усиление;&lt;br /&gt;
::''Baisλ'' - радиометрическое смещение.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
После обсчёта каждого пикселя геоснимка с использованием данной формулы, получаем матрицу значений c плавающей точкой - нормализованных геоданных. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
==&amp;lt;b&amp;gt;Атмосферная коррекция&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Следующим этапом нормализации геоданных является уменьшение влияния атмосферы на снимок и перевод значений радиации, дошедшей до сенсоров спутника (TOA radiance), в значения реально отражённого от земли спектрального излучения солнечного света.&lt;br /&gt;
&lt;br /&gt;
Материалы данного и последующих разделов, в некоторой степени, перекликаются со статьёй [http://gis-lab.info/qa/atcor.html &amp;quot;Атмосферная коррекция данных Landsat/ETM+ (COST метод)&amp;quot;], но в отличии от неё ориентированы на пакетную обработку ДДЗ из нескольких источников.&lt;br /&gt;
&lt;br /&gt;
Влияние атмосферы на геоснимок проявляется в целом ряде факторов: угол падения и отражения солнечных лучей, прозрачность атмосферы, газовый фактор и дымка (Рисунок 1).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Файл:Dos_img_1.jpg]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Рисунок 1 — Факторы, влияющие на попадание отраженной солнечной радиации на сенсоры спутника&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Для дальнейших исследований необходимо провести оптическую коррекцию (нормализацию) данных геоснимка методом Dark Object Subtraction (DOS), впервые представленным Chavez (1996) [5]. Суть метода состоит в нахождении яркости однопроцентно тёмного объекта геоснимка с последующей коррекцией минимума значений каждого пикселя изображения, относительно спектральной яркости найденного объекта.&lt;br /&gt;
&lt;br /&gt;
Есть два основных способа поиска 1% темного объекта (Dark Object) для метода DOS:&lt;br /&gt;
# эмпирический метод - подразумевает поиск значений в ручном режиме, например, с использованием инструмента гистограмма в QGIS, где изменяя нижний порог яркости гистограммы постепенно находим примерное значение яркости искомого тёмного объекта;&lt;br /&gt;
#вычислительный метод подразумевает, что суммарная яркость (от 0 до n) однопроцентно тёмного объекта будет соответствовать 0.01% от суммарной яркости всех пикселей геоснимка Sobrino et al., 2004 [6].&lt;br /&gt;
В данной работе успешно применяли метод (2), хорошо показавший себя при обработке большого количества геоснимков исследуемого района.&lt;br /&gt;
&lt;br /&gt;
После определения яркости Dark Object (в дальнейших вычислениях будем обозначать его как DNmin), производим атмосферную коррекцию по методу DOS в несколько этапов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
====1.Вычисляем значение радиации, соответствующее значению яркости 1% темного объекта (расчёт производится по аналогии с TOA radiance), по формуле (3).====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_03.png]]    (3)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта;&lt;br /&gt;
::''DNmin'' - значения яркости пикселя 1% тёмного объекта;&lt;br /&gt;
::''Qcalmin'' - минимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''Qcalmax'' - максимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''LMINλ'' - минимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка;&lt;br /&gt;
::''LMAXλ'' - максимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка.    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Или с использованием упрощённой формы (4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''Lλmin = DNmin × Gainλ + Baisλ'' (4)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта;&lt;br /&gt;
::''DNmin'' - значения яркости пикселя 1% тёмного объекта;&lt;br /&gt;
::''Gainλ'' - радиометрическое усиление;&lt;br /&gt;
::''Baisλ'' - радиометрическое смещение.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
====2.Рассчитываем коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта по формуле (5).====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_05.png]] (5)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' - коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта;&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''E&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;'' - коэффициент солнечного внеатмосферного спектрального излучения (явно представлен как табличные данные и учитывается при калибровке датчиков Landsat 5 и 7 , для Landsat 8 дополнительно вычисляется);&lt;br /&gt;
::''θ'' - зенитное расстояние для солнца в радианах;&lt;br /&gt;
::''T&amp;lt;sub&amp;gt;Z&amp;lt;/sub&amp;gt;'' - мера прохождения излучения от солнца до земли, в методе DOS2, принимается равным cosθ.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
====3.Вычисляем значение атмосферной дымки (hazing) по формуле (6).====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''Lλhaze = Lλmin - L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' (6)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλhaze'' - значение атмосферной дымки (hazing);&lt;br /&gt;
::''L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' - коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта;&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
====4.Рассчитываем атмосферно скорректированные значения отражённой солнечной радиации по формуле (7).====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_07.png]] (7)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''ρλ'' - атмоферно скорректированные значения отражённой солнечной радиации;&lt;br /&gt;
::''Lλ'' - значения радиации пришедшей на сенсор спутника;&lt;br /&gt;
::''Lλhaze'' - значение атмосферной дымки (hazing);&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''E&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;'' - коэффициент солнечного внеатмосферного спектрального излучения (явно представлен как табличные данные и учитывается при калибровке датчиков Landsat 5 и 7 , для Landsat 8 дополнительно вычисляется);&lt;br /&gt;
::''θ'' - зенитное расстояние для солнца в радианах;&lt;br /&gt;
::''T&amp;lt;sub&amp;gt;Z&amp;lt;/sub&amp;gt;'' - мера прохождения излучения от солнца до земли, в методе DOS2, принимается равным cosθ.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
==&amp;lt;b&amp;gt;Особенности работы с растрами спутника Landsat 8&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Если часть сцен сняты спутником Landsat 8 датчик Oli, необходимость их сравнения со сценами спутников lansat5 (датчик TM) и landsat8 (датчик ETM+). В данном контексте известна проблема применения стандартных методов атмосферной коррекции для нового спутника: дело в том, что калибровка датчиков Oli Landsat 8 производится без учёта значений коэффициента солнечного внеатмосферного спектрального излучения Eo (Sobrino et al., 2004) [6] или ,в других источниках, Esun. Вместо использования данного коэффициента, в файл корректировки _MTL.txt, были добавлены некоторые новые спектральные параметры: REFLECTANCE_MULT_BAND - усиление значения отражения и REFLECTANCE_ADD_BAND - смещение значения отражения для каждого из спектральных датчиков. В результате, по задумке авторов изменений, расчет TOA reflectance для Landsat 8 должен производится по формуле (8).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''ρλ' = MρQcal+ Aρ'' (8)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где: &lt;br /&gt;
::''ρλ''' - значение верхнеатмосфеного планетарного отражения радиации (TOA reflectance), без учёта коррекции по углу падения и отражения солнечных лучей;&lt;br /&gt;
::''Mρ'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_MULT_BAND_x, где x это номер канала) - усиление значения отражения;&lt;br /&gt;
::''Aρ'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_ADD_BAND_x,где x это номер канала) - смещение значения отражения;&lt;br /&gt;
::''Qcal'' - значения яркости пикселя сырого геоснимка (DN).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
А коррекция TOA reflectance с учётом угла падения и отражения солнечных лучей вычисляется по формуле (9).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_09.png]] (9)                               &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где: &lt;br /&gt;
::''ρλ'' - значение верхнеатмосфеного планетарного отражения радиации (TOA reflectance), c учётом коррекции по углу падения и отражения солнечных лучей;&lt;br /&gt;
::''θSE'' - высота солнца над горизонтом. Доступна в файле _MTL.txt в параметре (SUN_ELEVATION);&lt;br /&gt;
::''θSZ'' - зенитное расстояние; θSZ = 90° - θSE.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Сообщество разработчиков свободной GIS GRASS указывает на одинаковые значения REFLECTANCE_MULT_BAND и REFLECTANCE_ADD_BAND для всех каналов снимка [8], что не может быть в реальности. Данная группа разработчиков в своём модуле нормализации и атмосферной коррекции i.landsat.toar применяет к георастрам, снятым при помощи датчиков Oli Landsat 8, те же математические методы, что для TM Landsat 5 и ETM+ Landsat 7, а недостающий коэффициент Eo (Esun) рассчитывает по формуле (10).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_10.png]] (10)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Esun'' - (E0) вычисленный коэффициент солнечного внеатмосферного спектрального излучения;&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''RADIANCE_MAXIMUM'' - каналоспецифичный мультипликативный расчётный фактор для (RADIANCE_MAXIMUM_x, где x это номер канала) - максимально возможное значение поступающей на сенсор радиации;&lt;br /&gt;
::''REFLECTANCE_MAXIMUM'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_MAXIMUM_x, где x это номер канала) - максимальное значение радиации, отражённой от поверхности земли.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Ещё одной особенностью Landsat8 стало уменьшение чувствительности каналов RED, NIR и SWIR1 относительно Landsat 7 и 5 , что приводит к изменению значений, вычисляемых с использованием данных спектров, индексов.&lt;br /&gt;
&lt;br /&gt;
Данную проблему пытался решить Neil Flood, 2014 [9] введением дополнительных, рассчитанных им эмпирическим путём, коэффициентов для каждого канала геоснимка. В результате, коррекция значений TOA reflectance Landsat8 в значения для того же региона и тех же спектров Landsat7, приобретает вид формулы (11).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''ρETM+ = c0 + c1 × ρOLI'' (11)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''ρETM'' - результат конвертирования значения TOA reflectance из Landsat 8 в Landsat 7;&lt;br /&gt;
::''ρOLI'' - вычисленное для Landsat8 значение TOA reflectance;&lt;br /&gt;
::''c0'' - смещение значения отражённой радиации между датчиками OLI и ETM+;&lt;br /&gt;
::''c1'' - усиление значения отражённой радиации между датчиками OLI и ETM+.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Значения c0 и с1 формулы (11) были сведены автором в корректировочные таблицы, что позволяет применять их без повторения вычислений представленных в статье Neil Flood, 2014 [9].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Программная реализация нормализации геоснимков для трёх типов спутников Landsat: 5,7,8&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Все вычисления производились с использованием языка программирования python. Для этого была написана собственная программа нормализации геоданных с использованием интерфейса GDAL (библиотеки для работы с растровыми географическими форматами), тесно связанного с расширением numpy, добавляющим в язык программирования поддержку больших многомерных массивов и матриц, а также систему низкоуровневых математических функций для операций с этими массивами. Программа состоит из следующих структурных элементов:&lt;br /&gt;
&lt;br /&gt;
#Класса преобразования растра в массив.&lt;br /&gt;
#Класса преобразования вычисленного массива в растр.&lt;br /&gt;
#Класса сбора данных коррекции при помощи парсера _MTL.txt файла и данных выгрузки расстояний от земли до солнца [7].&lt;br /&gt;
#Выполняемого скрипта самих математических вычислений растров для проведения процесса нормализации.&lt;br /&gt;
&lt;br /&gt;
Исходные коды программы доступны для загрузки по адресу: https://github.com/oldbay/raster_tools, кроме того исходные GEOTIFF и нормализованные спектральные растры доступны по адресу: https://github.com/oldbay/paper_examples&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
==&amp;lt;b&amp;gt;Список использованных источников&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
# Официальный сайт Геологической Службы Соединённых Штатов - USGS [Электронный ресурс]. Режим доступа: http://www.usgs.gov.&lt;br /&gt;
# Интреактивный WEB-интерфейс получения данных дистанционного зондирования с ресурса Геологической Службы Соединённых Штатов [Электронный ресурс]. Режим доступа: http://glovis.usgs.gov.&lt;br /&gt;
# Thome K.J., Biggar S.F., Gellman D.L., Slater P.N. (1994) - Absolute-radiometric calibration of Landsat-5 Thematic Mapper and the proposed calibration of the Advanced Spaceborne Thermal Emission and Reflection Radiometer. Paper presented at the Geoscience and Remote Sensing Symposium, 1994. IGARSS’94. Surface and Atmospheric Remote Sensing: Technologies, Data Analysis and Interpretation.&lt;br /&gt;
# Lu D., Mausel P., Brondizio E., Moran E. (2002) - Assessment of atmospheric correction methods for Landsat TM data applicable to Amazon basin LBA research. International Journal of Remote Sensing, 23 (13): 2651-2671.&lt;br /&gt;
# Chavez, P. S. (1996). Image-based atmospheric correction—revisited and improved. Photogrammetric Engineering and Remote Sensing, 62(9), 1025 – 1036.&lt;br /&gt;
# Sobrino J. A., Jiménez-Muñoz J.C., Paolini L. (2004) - Land surface temperature retrieval from LANDSAT TM 5. Remote sensing of Environment, 90 (4): 434-440.&lt;br /&gt;
# «HORIZONS Web-Interface» [Electronic resource]. Access mode: http://ssd.jpl.nasa.gov/horizons.cgi.&lt;br /&gt;
# «Calculates top-of-atmosphere radiance or reflectance and temperature for Landsat MSS/TM/ETM+/OLI» [Electronic resource]. Access mode: http://grass.osgeo.org/grass65/manuals/i.landsat.toar.html.&lt;br /&gt;
# Neil Flood (2014) Continuity of Reflectance Data between Landsat-7 ETM+ and Landsat-8 OLI, for Both Top-of-Atmosphere and Surface Reflectance: A Study in the Australian Landscape. Remote Sens. 2014, 6, 7952-7970&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
	<entry>
		<id>https://wiki.gis-lab.info/index.php?title=%D0%90%D1%82%D0%BC%D0%BE%D1%81%D1%84%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D0%BA%D0%BE%D1%80%D1%80%D0%B5%D0%BA%D1%86%D0%B8%D1%8F_%D0%BF%D0%BE_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%83_DOS&amp;diff=22214</id>
		<title>Атмосферная коррекция по методу DOS</title>
		<link rel="alternate" type="text/html" href="https://wiki.gis-lab.info/index.php?title=%D0%90%D1%82%D0%BC%D0%BE%D1%81%D1%84%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D0%BA%D0%BE%D1%80%D1%80%D0%B5%D0%BA%D1%86%D0%B8%D1%8F_%D0%BF%D0%BE_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D1%83_DOS&amp;diff=22214"/>
		<updated>2015-07-18T19:05:28Z</updated>

		<summary type="html">&lt;p&gt;Oldbay: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Статья|Черновик}}&lt;br /&gt;
==&amp;lt;b&amp;gt;Анотация&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Недавно была защищена магистерская диссертация по ГИС тематике, решил выдержки из данной работы опубликовать в виде цикла статей. В первой статье рассмотрим атмосферную коррекцию по методу DOS (Dark Object Subtraction). В конце статьи представлен готовый программный инструментарий для выполения атмосферной коррекции.&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Подготовка геоданных&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Среди источников геоданных использовались данные USGS (Геологической Службы Соединённых Штатов) [1] доступных для свободного скачивания [2]. Данные с этих ресурсов представлены в формате GeoTIFF в виде непрерывных наборов сцен для различных районов мира. Представленные на ресурсах геоданные соответствуют уровню обработки LG1: «сырые геоданные» не конвертированные в значения излучения на сенсоре. Для самостоятельного проведения конвертации и атмосферной коррекции - доступны файлы настройки спутниковых сенсоров с набором ряда параметров: минимумы и максимумы пиксельной яркости на изображении; минимумы и максимумы излучения на датчиках; минимумы и максимумы отражения излучения от поверхности земли (Landsat 8) и многое другое. Кроме данных настройки спутниковых датчиков в архиве присутствуют несколько файлов в формате GeoTIFF, распределённых по номерам каналов, количество и состав которых для разных спутников (Landsat 5,7,8) различный (Таблица 1).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Таблица 1 — Спутники и используемые в работе каналы&lt;br /&gt;
{|class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
 !Спутник и датчик&lt;br /&gt;
 !Порядковый номер канала (band)&lt;br /&gt;
 !Название спектра&lt;br /&gt;
 !Длинны волн (нм)&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Landsat 5 TM&lt;br /&gt;
 |1&lt;br /&gt;
 |Blue - Синий&lt;br /&gt;
 |450–520&lt;br /&gt;
 |-&lt;br /&gt;
 |2&lt;br /&gt;
 |Green - Зелёный&lt;br /&gt;
 |520–600&lt;br /&gt;
 |-&lt;br /&gt;
 |3&lt;br /&gt;
 |Red - Красный&lt;br /&gt;
 |630–690&lt;br /&gt;
 |-&lt;br /&gt;
 |4&lt;br /&gt;
 |NIR — Ближний ИК&lt;br /&gt;
 |760–900&lt;br /&gt;
 |-&lt;br /&gt;
 |5&lt;br /&gt;
 |SWIR1 — Средний ИК 1&lt;br /&gt;
 |1550–1750&lt;br /&gt;
 |-&lt;br /&gt;
 |7&lt;br /&gt;
 |SWIR2 — Средний ИК 2&lt;br /&gt;
 |2080–2350&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Landsat 7 ETM+&lt;br /&gt;
 |1&lt;br /&gt;
 |Blue - Синий&lt;br /&gt;
 |450–520&lt;br /&gt;
 |-&lt;br /&gt;
 |2&lt;br /&gt;
 |Green - Зелёный&lt;br /&gt;
 |520–600&lt;br /&gt;
 |-&lt;br /&gt;
 |3&lt;br /&gt;
 |Red - Красный&lt;br /&gt;
 |630–690&lt;br /&gt;
 |-&lt;br /&gt;
 |4&lt;br /&gt;
 |NIR — Ближний ИК&lt;br /&gt;
 |770–900&lt;br /&gt;
 |-&lt;br /&gt;
 |5&lt;br /&gt;
 |SWIR1 — Средний ИК 1&lt;br /&gt;
 |1550–1750&lt;br /&gt;
 |-&lt;br /&gt;
 |7&lt;br /&gt;
 |SWIR2 — Средний ИК 2&lt;br /&gt;
 |2080–2350&lt;br /&gt;
 |-&lt;br /&gt;
 !rowspan=&amp;quot;6&amp;quot;|Lansat 8 Oli&lt;br /&gt;
 |2&lt;br /&gt;
 |Blue - Синий&lt;br /&gt;
 |450—515&lt;br /&gt;
 |-&lt;br /&gt;
 |3&lt;br /&gt;
 |Green - Зелёный&lt;br /&gt;
 |525—600&lt;br /&gt;
 |-&lt;br /&gt;
 |4&lt;br /&gt;
 |Red - Красный&lt;br /&gt;
 |630—680&lt;br /&gt;
 |-&lt;br /&gt;
 |5&lt;br /&gt;
 |NIR — Ближний ИК&lt;br /&gt;
 |845—885&lt;br /&gt;
 |-&lt;br /&gt;
 |6&lt;br /&gt;
 |SWIR1 — Средний ИК 1&lt;br /&gt;
 |1560—1660&lt;br /&gt;
 |-&lt;br /&gt;
 |7&lt;br /&gt;
 |SWIR2 — Средний ИК 2&lt;br /&gt;
 |2100—2300&lt;br /&gt;
 |}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Как видно из таблицы, шесть наиболее используемых «спектров» находятся у разных спутников в сходном диапазоне частот. Поэтому, для удобства использования терминологии, вместо указания спутниковых каналов в дальнейшем будем использовать самоназвание спектров: BLUE - синий, GREEN - зелёный, RED - красный, NIR - ближний инфракрасный, SWIR1 - средний инфракрасный 1, SWIR2 - средний инфракрасный 2 - вне зависимости от спутника и применять к ним одинаковый набор вычислений.&lt;br /&gt;
&lt;br /&gt;
Как уже упоминалось, геоданные по всем каналам предоставлены уровнем обработки LG1 - в сыром виде, это означает что предоставленные канальные GeoTIFF не более чем спозиционированные на местности яркостные «фотографии», которые, в таком виде, не могут быть использованы для ГИС исследований. Поэтому данные уровня обработки LG1 необходимо нормализовать - то есть провести конвертацию значений яркости в показатели излучения на сенсоре и атмосферную коррекцию.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Конвертация значений яркости исходного GeoTIFF в показатели излучения на сенсоре&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Теоретические основы процесса конвертирования подробно описаны в статье [http://gis-lab.info/qa/dn2radiance.html 'Конвертация данных TM, ETM+ в показатели излучения на сенсоре'], потому коснёмся только практической реализации процесса.&lt;br /&gt;
&lt;br /&gt;
Конвертирование является первым этапом нормализации сырых геоданных и представляет из себя математическую операцию перевода значения яркости пикселей геоснимка в значения радиации поступившей на датчики спутника. Для такого перевода в комплекте данных Landsat присутствует файл коррекции _MTL.txt, предельные значения из которого и используются на этом этапе обработки геоснимка.&lt;br /&gt;
&lt;br /&gt;
Для проведения работы использовалась стандартная, описанная в документации NASA, формула (1) перевода яркости в значение top of atmosphere radiance (TOA radiance) &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:F_01.png]]    (1)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλ'' - спектральная радиация, пришедшая на сенсор спутника;&lt;br /&gt;
::''DNcal'' - значения яркости пикселя сырого геоснимка;&lt;br /&gt;
::''Qcalmin'' - минимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''Qcalmax'' - максимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''LMINλ'' - минимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка;&lt;br /&gt;
::''LMAXλ'' - максимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Кроме того для вычисления TOA radiance можно использовать упрощенную формулу (2) Thome et al., 1994 [3], Lu et al 2002 [4].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''Lλ = DNcal × Gainλ + Baisλ''    (2)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλ'' - спектральная радиация, пришедшая на сенсор спутника;&lt;br /&gt;
::''DNcal'' - значения яркости пикселя сырого геоснимка;&lt;br /&gt;
::''Gainλ'' - радиометрическое усиление;&lt;br /&gt;
::''Baisλ'' - радиометрическое смещение.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
После обсчёта каждого пикселя геоснимка с использованием данной формулы, получаем матрицу значений c плавающей точкой - нормализованных геоданных. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
==&amp;lt;b&amp;gt;Атмосферная коррекция&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Следующим этапом нормализации геоданных является уменьшение влияния атмосферы на снимок и перевод значений радиации, дошедшей до сенсоров спутника (TOA radiance), в значения реально отражённого от земли спектрального излучения солнечного света.&lt;br /&gt;
&lt;br /&gt;
Материалы данного и последующих разделов, в некоторой степени, перекликаются со статьёй [http://gis-lab.info/qa/atcor.html &amp;quot;Атмосферная коррекция данных Landsat/ETM+ (COST метод)&amp;quot;], но в отличии от неё ориентированы на пакетную обработку ДДЗ из нескольких источников.&lt;br /&gt;
&lt;br /&gt;
Влияние атмосферы на геоснимок проявляется в целом ряде факторов: угол падения и отражения солнечных лучей, прозрачность атмосферы, газовый фактор и дымка (Рисунок 1).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
[[Файл:Dos_img_1.jpg]]&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Рисунок 1 — Факторы, влияющие на попадание отраженной солнечной радиации на сенсоры спутника&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Для дальнейших исследований необходимо провести оптическую коррекцию (нормализацию) данных геоснимка методом Dark Object Subtraction (DOS), впервые представленным Chavez (1996) [5]. Суть метода состоит в нахождении яркости однопроцентно тёмного объекта геоснимка с последующей коррекцией минимума значений каждого пикселя изображения, относительно спектральной яркости найденного объекта.&lt;br /&gt;
&lt;br /&gt;
Есть два основных способа поиска 1% темного объекта (Dark Object) для метода DOS:&lt;br /&gt;
# эмпирический метод - подразумевает поиск значений в ручном режиме, например, с использованием инструмента гистограмма в QGIS, где изменяя нижний порог яркости гистограммы постепенно находим примерное значение яркости искомого тёмного объекта;&lt;br /&gt;
#вычислительный метод подразумевает, что суммарная яркость (от 0 до n) однопроцентно тёмного объекта будет соответствовать 0.01% от суммарной яркости всех пикселей геоснимка Sobrino et al., 2004 [6].&lt;br /&gt;
В данной работе успешно применяли метод (2), хорошо показавший себя при обработке большого количества геоснимков исследуемого района.&lt;br /&gt;
&lt;br /&gt;
После определения яркости Dark Object (в дальнейших вычислениях будем обозначать его как DNmin), производим атмосферную коррекцию по методу DOS в несколько этапов:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
===1.Вычисляем значение радиации, соответствующее значению яркости 1% темного объекта (расчёт производится по аналогии с TOA radiance), по формуле (3).===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_03.png]]    (3)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта;&lt;br /&gt;
::''DNmin'' - значения яркости пикселя 1% тёмного объекта;&lt;br /&gt;
::''Qcalmin'' - минимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''Qcalmax'' - максимальное возможное значение пикселя геоснимка;&lt;br /&gt;
::''LMINλ'' - минимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка;&lt;br /&gt;
::''LMAXλ'' - максимальное значение спектральной радиации для конкретного датчика спутника для конкретного снимка.    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Или с использованием упрощённой формы (4).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''Lλmin = DNmin × Gainλ + Baisλ'' (4)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта;&lt;br /&gt;
::''DNmin'' - значения яркости пикселя 1% тёмного объекта;&lt;br /&gt;
::''Gainλ'' - радиометрическое усиление;&lt;br /&gt;
::''Baisλ'' - радиометрическое смещение.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
===2.Рассчитываем коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта по формуле (5).===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_05.png]] (5)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' - коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта;&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''E&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;'' - коэффициент солнечного внеатмосферного спектрального излучения (явно представлен как табличные данные и учитывается при калибровке датчиков Landsat 5 и 7 , для Landsat 8 дополнительно вычисляется);&lt;br /&gt;
::''θ'' - зенитное расстояние для солнца в радианах;&lt;br /&gt;
::''T&amp;lt;sub&amp;gt;Z&amp;lt;/sub&amp;gt;'' - мера прохождения излучения от солнца до земли, в методе DOS2, принимается равным cosθ.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
===3.Вычисляем значение атмосферной дымки (hazing) по формуле (6).===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''Lλhaze = Lλmin - L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' (6)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Lλhaze'' - значение атмосферной дымки (hazing);&lt;br /&gt;
::''L&amp;lt;sub&amp;gt;1%&amp;lt;/sub&amp;gt;'' - коэффициент влияния угла падения и отражения солнечных лучей для 1% тёмного объекта;&lt;br /&gt;
::''Lλmin'' - спектральная радиация для 1% тёмного объекта.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
===4.Рассчитываем атмосферно скорректированные значения отражённой солнечной радиации по формуле (7).===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_07.png]] (7)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''ρλ'' - атмоферно скорректированные значения отражённой солнечной радиации;&lt;br /&gt;
::''Lλ'' - значения радиации пришедшей на сенсор спутника;&lt;br /&gt;
::''Lλhaze'' - значение атмосферной дымки (hazing);&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''E&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;'' - коэффициент солнечного внеатмосферного спектрального излучения (явно представлен как табличные данные и учитывается при калибровке датчиков Landsat 5 и 7 , для Landsat 8 дополнительно вычисляется);&lt;br /&gt;
::''θ'' - зенитное расстояние для солнца в радианах;&lt;br /&gt;
::''T&amp;lt;sub&amp;gt;Z&amp;lt;/sub&amp;gt;'' - мера прохождения излучения от солнца до земли, в методе DOS2, принимается равным cosθ.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
==&amp;lt;b&amp;gt;Особенности работы с растрами спутника Landsat 8&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Если часть сцен сняты спутником Landsat 8 датчик Oli, необходимость их сравнения со сценами спутников lansat5 (датчик TM) и landsat8 (датчик ETM+). В данном контексте известна проблема применения стандартных методов атмосферной коррекции для нового спутника: дело в том, что калибровка датчиков Oli Landsat 8 производится без учёта значений коэффициента солнечного внеатмосферного спектрального излучения Eo (Sobrino et al., 2004) [6] или ,в других источниках, Esun. Вместо использования данного коэффициента, в файл корректировки _MTL.txt, были добавлены некоторые новые спектральные параметры: REFLECTANCE_MULT_BAND - усиление значения отражения и REFLECTANCE_ADD_BAND - смещение значения отражения для каждого из спектральных датчиков. В результате, по задумке авторов изменений, расчет TOA reflectance для Landsat 8 должен производится по формуле (8).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''ρλ' = MρQcal+ Aρ'' (8)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где: &lt;br /&gt;
::''ρλ''' - значение верхнеатмосфеного планетарного отражения радиации (TOA reflectance), без учёта коррекции по углу падения и отражения солнечных лучей;&lt;br /&gt;
::''Mρ'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_MULT_BAND_x, где x это номер канала) - усиление значения отражения;&lt;br /&gt;
::''Aρ'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_ADD_BAND_x,где x это номер канала) - смещение значения отражения;&lt;br /&gt;
::''Qcal'' - значения яркости пикселя сырого геоснимка (DN).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
А коррекция TOA reflectance с учётом угла падения и отражения солнечных лучей вычисляется по формуле (9).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_09.png]] (9)                               &lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где: &lt;br /&gt;
::''ρλ'' - значение верхнеатмосфеного планетарного отражения радиации (TOA reflectance), c учётом коррекции по углу падения и отражения солнечных лучей;&lt;br /&gt;
::''θSE'' - высота солнца над горизонтом. Доступна в файле _MTL.txt в параметре (SUN_ELEVATION);&lt;br /&gt;
::''θSZ'' - зенитное расстояние; θSZ = 90° - θSE.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Сообщество разработчиков свободной GIS GRASS указывает на одинаковые значения REFLECTANCE_MULT_BAND и REFLECTANCE_ADD_BAND для всех каналов снимка [8], что не может быть в реальности. Данная группа разработчиков в своём модуле нормализации и атмосферной коррекции i.landsat.toar применяет к георастрам, снятым при помощи датчиков Oli Landsat 8, те же математические методы, что для TM Landsat 5 и ETM+ Landsat 7, а недостающий коэффициент Eo (Esun) рассчитывает по формуле (10).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::[[Файл:Dos_f_10.png]] (10)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''Esun'' - (E0) вычисленный коэффициент солнечного внеатмосферного спектрального излучения;&lt;br /&gt;
::''d'' - расстояние от солнца до земли в астрономических единицах в конкретный день съёмки сцены на конкретной местности [7];&lt;br /&gt;
::''RADIANCE_MAXIMUM'' - каналоспецифичный мультипликативный расчётный фактор для (RADIANCE_MAXIMUM_x, где x это номер канала) - максимально возможное значение поступающей на сенсор радиации;&lt;br /&gt;
::''REFLECTANCE_MAXIMUM'' - каналоспецифичный мультипликативный расчётный фактор для (REFLECTANCE_MAXIMUM_x, где x это номер канала) - максимальное значение радиации, отражённой от поверхности земли.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Ещё одной особенностью Landsat8 стало уменьшение чувствительности каналов RED, NIR и SWIR1 относительно Landsat 7 и 5 , что приводит к изменению значений, вычисляемых с использованием данных спектров, индексов.&lt;br /&gt;
&lt;br /&gt;
Данную проблему пытался решить Neil Flood, 2014 [9] введением дополнительных, рассчитанных им эмпирическим путём, коэффициентов для каждого канала геоснимка. В результате, коррекция значений TOA reflectance Landsat8 в значения для того же региона и тех же спектров Landsat7, приобретает вид формулы (11).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
::''ρETM+ = c0 + c1 × ρOLI'' (11)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
где:&lt;br /&gt;
::''ρETM'' - результат конвертирования значения TOA reflectance из Landsat 8 в Landsat 7;&lt;br /&gt;
::''ρOLI'' - вычисленное для Landsat8 значение TOA reflectance;&lt;br /&gt;
::''c0'' - смещение значения отражённой радиации между датчиками OLI и ETM+;&lt;br /&gt;
::''c1'' - усиление значения отражённой радиации между датчиками OLI и ETM+.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Значения c0 и с1 формулы (11) были сведены автором в корректировочные таблицы, что позволяет применять их без повторения вычислений представленных в статье Neil Flood, 2014 [9].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;b&amp;gt;Программная реализация нормализации геоснимков для трёх типов спутников Landsat: 5,7,8&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
Все вычисления производились с использованием языка программирования python. Для этого была написана собственная программа нормализации геоданных с использованием интерфейса GDAL (библиотеки для работы с растровыми географическими форматами), тесно связанного с расширением numpy, добавляющим в язык программирования поддержку больших многомерных массивов и матриц, а также систему низкоуровневых математических функций для операций с этими массивами. Программа состоит из следующих структурных элементов:&lt;br /&gt;
&lt;br /&gt;
#Класса преобразования растра в массив.&lt;br /&gt;
#Класса преобразования вычисленного массива в растр.&lt;br /&gt;
#Класса сбора данных коррекции при помощи парсера _MTL.txt файла и данных выгрузки расстояний от земли до солнца [7].&lt;br /&gt;
#Выполняемого скрипта самих математических вычислений растров для проведения процесса нормализации.&lt;br /&gt;
&lt;br /&gt;
Исходные коды программы доступны для загрузки по адресу: https://github.com/oldbay/raster_tools, кроме того исходные GEOTIFF и нормализованные спектральные растры доступны по адресу: https://github.com/oldbay/paper_examples&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
==&amp;lt;b&amp;gt;Список использованных источников&amp;lt;/b&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
# Официальный сайт Геологической Службы Соединённых Штатов - USGS [Электронный ресурс]. Режим доступа: http://www.usgs.gov.&lt;br /&gt;
# Интреактивный WEB-интерфейс получения данных дистанционного зондирования с ресурса Геологической Службы Соединённых Штатов [Электронный ресурс]. Режим доступа: http://glovis.usgs.gov.&lt;br /&gt;
# Thome K.J., Biggar S.F., Gellman D.L., Slater P.N. (1994) - Absolute-radiometric calibration of Landsat-5 Thematic Mapper and the proposed calibration of the Advanced Spaceborne Thermal Emission and Reflection Radiometer. Paper presented at the Geoscience and Remote Sensing Symposium, 1994. IGARSS’94. Surface and Atmospheric Remote Sensing: Technologies, Data Analysis and Interpretation.&lt;br /&gt;
# Lu D., Mausel P., Brondizio E., Moran E. (2002) - Assessment of atmospheric correction methods for Landsat TM data applicable to Amazon basin LBA research. International Journal of Remote Sensing, 23 (13): 2651-2671.&lt;br /&gt;
# Chavez, P. S. (1996). Image-based atmospheric correction—revisited and improved. Photogrammetric Engineering and Remote Sensing, 62(9), 1025 – 1036.&lt;br /&gt;
# Sobrino J. A., Jiménez-Muñoz J.C., Paolini L. (2004) - Land surface temperature retrieval from LANDSAT TM 5. Remote sensing of Environment, 90 (4): 434-440.&lt;br /&gt;
# «HORIZONS Web-Interface» [Electronic resource]. Access mode: http://ssd.jpl.nasa.gov/horizons.cgi.&lt;br /&gt;
# «Calculates top-of-atmosphere radiance or reflectance and temperature for Landsat MSS/TM/ETM+/OLI» [Electronic resource]. Access mode: http://grass.osgeo.org/grass65/manuals/i.landsat.toar.html.&lt;br /&gt;
# Neil Flood (2014) Continuity of Reflectance Data between Landsat-7 ETM+ and Landsat-8 OLI, for Both Top-of-Atmosphere and Surface Reflectance: A Study in the Australian Landscape. Remote Sens. 2014, 6, 7952-7970&lt;/div&gt;</summary>
		<author><name>Oldbay</name></author>
	</entry>
</feed>