Объединенные электронные атласы из многолистовых крупномасштабных карт XIX-XX веков. Теоретический минимум. Часть первая.
Теперь, когда мы поняли состояние дел с привязкой исторических карт и созданием из них электронных атласов, а также определились в целом с теми путями и методами, которыми мы будем решать имеющиеся задачи, самое время немного углубиться в вопросы теории, а заодно и определиться с терминологией, которую мы применяли в предыдущих вводных частях без всякого объяснения.
Начнем с самого простого, но очень важного вопроса: что вообще представляют собой те карты и атласы, с которыми мы будем иметь дело?
Почти все время мы с вами будем иметь дело не с исходными «бумажными» материалами, а с их электронными копиями, полученными тем или иным способом, но в большинстве случаев — простым сканированием исходного исторического образца. Таким образом, когда мы будем говорить «карта», чаще всего мы будем подразумевать именно карту в электронном формате. Электронных форматов для хранения карт существует великое множество, но все их можно разделить на векторные и растровые форматы. Отличие их в том, что в векторном формате все данные хранятся в виде наборов геометрических объектов (точек, линий и полигонов), каждый из которых имеет набор собственных атрибутов (например, цвет заливки у полигона). Растровый же формат представляет собой «мозаику» из отдельных точек (или пикселей [1]), при этом и здесь каждая точка может иметь какие-то атрибуты (также, скажем, цвет). Хотя исторические карты и можно преобразовать в векторные форматы, однако в этом цикле мы их рассматривать почти не будем, поскольку, как я упомянул выше, наиболее естественными и первичными форматами таких карт являются растровые, полученные в результате сканирования (или фотографирования) исходного образца. Хотя векторные форматы и могут быть полезны для создания отдельной карты, например, с границами губерний, это все же выходит за рамки нашего общего рассмотрения, поэтому мы оставим их лишь для вспомогательных целей (например, для задания границ обрезки растровой карты). Таким образом, в дальнейшем мы сосредоточимся почти только лишь на растровых картах, или растрах, как часто коротко их называют. А здесь мы с вами разберем еще несколько отличий, поскольку они нам помогут в понимании других теоретических концепций.
Таким отличием растровых форматов от векторных, и очень важным, является понятие разрешения. Разрешение в файле растра определяется очень просто: это количество точек на единицу длины (или ширины) изображения, то есть плотность точек. Обычно в графических файлах предполагается, что и по длине, и по ширине такое количество одинаково (так называемые «квадратные пиксели», термин, который часто можно встретить в различных настройках ГИС), но это совершенно не обязательно, и в дальнейшем мы с вами это встретим. Важно понимать, что упомянутая «плотность» не относится к физическому способу хранения данных внутри файла, а является довольно абстрактной величиной, которая показывает, какие размеры должно иметь изображение при выводе на печать, или (с определенными оговорками, о которых чуть ниже) на экран. Поэтому и информация о разрешении растра хранится в отдельной небольшой части файла, в которой хранятся и все прочие так называемые метаданные [2]. Можно понимать разрешение как инструкцию о том, какого размера должно получиться изображение, содержащее определенное количество точек по горизонтали и вертикали, когда мы его выводим на печать. Если разрешение растра равно, скажем, 300 точек в дюйме [3] и печатаем его мы с таким же разрешением, то и размеры напечатанной картинки будут в точности равны заданным размерам хранимого в файле изображения.
Немного по-другому выглядит вывод изображения на экран. Поскольку обычные экранные разрешения существенно меньше, чем возможности современных сканирующих или печатающих устройств, то и при выводе изображения на экран обычные программы (включая ГИС) умеют так смасштабировать изображение, чтобы при его отображении на экране размер был близок к тому, который мы можем получить при печати.
Получить информацию о разрешении, а также о том, что хранится в других метаданных растра, проще всего загрузив этот файл в QGIS в виде растрового слоя (пункт меню «Слой») и вызвав двойным щелчком диалоговое окно с этими свойствами.

Информация о растре, полученная таким способом, является вполне достаточной для работы с ним. Впрочем, есть еще несколько сторонних программ, в которых общая информация о растре и более детальные метаданные представлены очень подробным образом. Для примера приведу два рисунка из упомянутого в предыдущей части редактора растровой графики GIMP.
Общую информацию о растре здесь можно посмотреть в диалоговом окне «Свойства изображения», а подробную о метаданных — в диалоге «Просмотреть метаданные». Здесь стоит познакомиться еще с одним термином, которым часто заменяют термин «метаданные» для изображений, но который на самом деле обозначает стандарт хранения таких специальных метаданных. Это термин «EXIF» (Exchangeable Image File Format).

Обсуждение других программ для работы с метаданными файлов изображений выходит далеко за рамки нашего рассмотрения, скажу лишь здесь, что далеко не все форматы, используемые в ГИС, читаются этими программами, а только лишь самые распространенные (JPEG, TIFF, PNG и т. п.).
Разрешение для растровых форматов изображений, которые применяются в ГИС, не обязательно должно быть постоянным. Многие форматы поддерживают так называемые «пирамиды», когда внутри одного файла изображения можно хранить несколько слоев-изображений, которые имеют разные разрешения (обычно с кратностью изменения равной 2). Таков например, естественный формат хранения довольно популярного до сих пор формата .ozf (.ozfx), в нем в одном файле хранится сразу несколько слоев с последовательным уменьшением разрешения в 2, 4, 8, 16 и т. д. раз. Другим примером является пожалуй самый широко используемый в ГИС формат .tiff. В нем подобные «пирамиды» могут быть созданы отдельной программой или же алгоритмом, встроенным в ГИС. Создание пирамид существенно облегчает чтение файла при его отображении на экране, например, при загрузке в ГИС: программы умеют из набора имеющихся слоев с разными разрешениями выбрать тот слой, который необходим для требуемого масштаба изображения, не загружая всю остальную часть файла, которая в данный момент не требуется для вывода [4].
Из сказанного выше есть одно очень важное практическое свойство. Поскольку величина разрешения всегда ограничена, мы не можем бесконечно «увеличивать» изображение в растровом файле ни при его печати, ни при отображении на экране. Всегда наступит такой момент, когда структура точек станет видна невооруженным глазом. Как говорят, изображение «распадается на пиксели». Такая ситуация сильного увеличения изображена на рисунке ниже. Впрочем, у такого эффекта есть и полезная сторона: мы всегда можем найти на изображении совершенно определенную точку с тем, чтобы например добавить ей или изменить у нее какой-то атрибут.

Заканчивая с обсуждением разрешения, для сравнения обязательно стоит вспомнить и о векторных файлах. Про них обычно говорят, что понятие «разрешения» для них не имеет смысла, ведь как мы видели немного выше, они состоят из произвольных наборов геометрических фигур, а не из монолитного множества точек. Из этой верной посылки, впрочем, часто делают в целом неправильный вывод о том, что векторные изображения карт будут одинаково «хорошо» выглядеть при любом увеличении. Это справедливо для некоторых векторных форматов (например, шрифтов), поскольку объекты в них описываются некоторыми математическими кривыми. Но для большинства обычных форматов, которые используются для хранения изображений карт, это не так. Линии и полигоны в векторных форматах на самом деле представляют собой ограниченный набор точек-вершин, соединенных отрезками прямых, и следовательно, при увеличении изображения выше определенной величины мы с вами увидим не гладкие кривые, а ломаные линии. Для примера ниже приведен векторный файл, состоящий из одного полигона и открытый в программе QGIS в режиме редактирования его вершин. В таком режиме хорошо заметна его внутренняя «дискретная» структура.

Еще одним важным отличием растровых форматов от векторных является понятие глубины цвета (ее еще называют битностью изображения). Дело в том, что векторные изображения, как мы уже помним, состоят из отдельных геометрических фигур, которым, в зависимости от значений каких-то атрибутов, сама программа отображения может присваивать цвет, при этом цвет может быть абсолютно любым, ограниченным лишь способностями устройства вывода. Для растровых файлов это не так, как вы уже видели раньше, они состоят из отдельных точек и цвет каждой точки нужно как-то хранить.
Файл растрового изображения всегда представляет собой двоичный (бинарный) файл, где в каждом байте этого файла хранятся какие-то значения. Мы чуть выше уже видели, что в самом начале такого файла могут храниться, например, разнообразные метаданные. Остальная часть растрового файла изображения собственно и предназначена для хранения последовательности точек вместе с их цветом. А глубина цвета и определяется тем количеством байтов, которое для каждой точки отводится.
Хорошо известно, что внутри каждого байта можно хранить одно из 256 разных значений (от 0 до 255). Если мы закодируем какой-то цвет величиной из этого диапазона, то в одном байте мы сможем хранить всего лишь один из 256 цветов. Для полноцветных изображений этого обычно очень мало, и поэтому для хранения цвета каждой точки отводят два (16-битный цвет, примерно 65 тысяч разных цветов) байта, но гораздо чаще — четыре. Последний способ позволяет хранить в трех байтах значения цветов для каждого цветового канала (красного, зеленого и синего), что при смешивании их даст свыше 16 миллионов разных вариаций оттенков, а еще один байт отводится для хранения степени прозрачности каждой из точек изображения. Такая модель носит название RGBA и применяется для хранения полноцветных растровых изображений, например, спутниковых снимков в разных цветах или промежуточных временных изображений при преобразованиях карт с тем, чтобы при таких преобразованиях не происходило визуального изменения цветности изображения.
Очевидно, что для многих применений в картографии, особенно для хранения финальных изображений, RGBA-модель сильно избыточна и приводит к очень большому размеру файлов растров. К счастью, довольно часто можно обойтись способами, позволяющими уменьшить глубину цветности (и соответствующий размер итогового файла), ведь по сути электронное изображение представляет собой скан первоначальной бумажной карты, количество цветов на которой само по себе ограничено. Особенно это касается тех исторических карт, которые мы с вами будем изучать. Часто для их печати использовалась черно-белая гравюра или литографическое изображение с достаточно небольшим количеством оттенков. Поэтому нередко для достаточно качественного хранения информации о цвете хватает и одного байта. В нем можно хранить, например, 256 оттенков серого цвета для хорошего черно-белого изображения (так называемое одноканальное серое или grayscale) или один из 256 цветов заранее определенной палитры (само определение цветов палитры хранится также в отдельной области растрового файла). С последними «палеттированными» (paletted) изображениями мы с вами в дальнейшем еще не раз столкнемся, таковы, например изготовленные за последнюю пару десятилетий .gif- или ozf-файлы, в которых хранятся множество исторических карт [5]. Однако, немного забегая вперед, следует еще добавить, что однобайтные (8-битные, палеттированные) файлы изображений могут хорошо подходить для хранения конечного изображения, но совершенно не годятся, если нам необходимо делать какие-то распространенные преобразования растра. Подробнее эту проблему мы с вами обсудим, когда будем рассматривать так называемую передискретизацию.
Наконец, у тех объектов, которые мы с вами будем в дальнейшем изучать, есть еще одно, важнейшее свойство. Оно относится как к векторным форматам, так и к растровым, хотя и реализовано в каждом случае по-разному. Совершенно очевидно, что хотя растровым (или векторным) файлом с данными можно пользоваться как картой, например, просто его снова напечатав на бумаге, для того, чтобы он верно позиционировался внутри геоинформационной системы или программы навигации, он должен получить еще одно, но самое важное для нас свойство — геопривязку, или, как часто говорят короче, привязку.
На выборе этого термина хотелось бы остановиться подробнее, так как у него существует довольно много синонимов и в разных источниках можно встретить любой из них. Такое разнообразие берет свое начало из тех программ, которые были разработаны в различные годы и служили или служат для самых различных целей (например, полноценные геоинформационные системы, программы навигации и т.д.). Мы с вами в дальнейшем будем использовать именно термин «геопривязка», как устоявшийся и наиболее часто используемый внутри русскоговорящей аудитории перевод английского термина «georeferencing». Однако различные варианты следует знать, чтобы понимать, что во всех случаях речь идет об одном и том же. Так например, в популярной в прошлом программе OziExplorer это свойство (или процесс придания файлу с картой этого свойства) называется калибровкой. В более серьезной полноценной ГИС MapInfo сам процесс называется регистрацией (который впрочем, как устоялось в русскоязычной литературе, создает файл привязки или регистрации, тут можно встретить оба термина). В очень популярной в настоящее время программе Global Mapper, в ее англоязычном варианте процесс называется «rectification», то есть, буквально «исправление», впрочем, параллельно используется и термин «georeferencing». Но как мы с вами договорились в предыдущей части, для работы с картами мы будем использовать программу QGIS, а следовательно будем следовать терминологии принятой в ней (и как я уже сказал выше, наиболее устоявшуюся терминологию).
Что же понимается под геопривязкой? Это значит, что каждая точка вашего изображения-карты (не важно — векторной или растровой) должна получить координаты, однозначно определяющие ее положение на поверхности Земли. Координаты бывают различные, подробнее мы с вами разберем это в следующей части, а здесь для простоты (и с некоторым упрощением) будем полагать, что каждой точке изображения будут сопоставлены самые широко известные координаты — географические, то есть широта и долгота.
Нагляднее всего определяются координаты привязанных векторных карт. Поскольку векторные карты, как мы это видели чуть раньше, состоят из наборов точек, линий и полигонов, а линии и полигоны, в свою очередь, также описываются через наборы точек (только специальным образом упорядоченных), то каждой точке векторной карты эти координаты и присваиваются. В качестве примера на рисунке ниже приведен фрагмент векторного файла, открытого в текстовом редакторе [6], который я уже приводил выше, показывая его отображение в QGIS. Хорошо видно, что по большей части он состоит из набора пар координат долгота-широта, которые полностью описывают этот полигон.

Для растровых файлов все совсем не так. Можно сразу вспомнить, что растр по сути своей представляет собой прямоугольник с точно определенной внутренней «шириной» и «высотой», то есть, количеством точек (пикселей) по двум этим измерениям. А это значит, что нет никакой необходимости хранить информацию о координатах для каждой точки растра, ведь все точки связаны между собой в один монолитный прямоугольник. Во многих случаях достаточно указать координаты всего лишь двух точек — одну для указания положения одного из углов прямоугольного растра в реальном географическом пространстве, а другую — для точного указания его масштаба в этом пространстве! Более того, как мы с вами скоро увидим, когда подойдем к обсуждению трансформаций, этих двух точек нам хватит еще и на то, чтобы указать поворот этого прямоугольника, тем самым точно его зафиксировав. Если же мы добавим еще одну, третью точку, то сможем даже исказить исходный прямоугольник в параллелограмм, зафиксировав при необходимости его еще точнее. Простые геометрические принципы, которые здесь заложены, по сути в точности соответствуют тем, которые мы с вами увидим, когда подробнее будем изучать самостоятельную привязку растров, здесь же лишь скажу, что мораль из всего сказанного проста: для достаточно точного указания привязки растра достаточно иметь очень ограниченное количество параметров (в нашем примере от трех до шести [7]). Столько обычно и используют.
Обязательно следует знать, что есть два принципиально различных способа указания привязки. Первый сопоставляет «пиксельные» координаты растра (фактически, «номера» точки растра по ширине и высоте) реальным координатам. Так устроены широко известные map-файлы, которые берут свое начало еще в программе OziExplorer, но до сих пор используются для совместимости с некоторыми другими программами или в тех случаях, когда другие способы указания привязки недоступны. Аналогичным образом, «поточечная» привязка используется в файлах привязки .TAB программы MapInfo. То, как будет вести себя программа, интерпретирующая такой способ, целиком зависит от самой программы, особенно в том случае, если точек привязки указано более двух [8]. Но есть и второй способ: явно указать программе, что ей нужно сделать с растром, например, перечислив параметры такого преобразования. Так устроен самый широко используемый способ указания привязки с помощью world-файла. В нем как раз и перечислены все те шесть параметров, о которых шла речь выше (впрочем, некоторые параметры могут иметь и нулевую величину, тем самым упрощая работу алгоритма чтения такого способа привязки). На рисунке ниже приведено типичное содержимое world-файла [9].

Наконец, существуют два способа хранения привязки. Ее можно хранить в отдельном файле, который так и называется файлом привязки, примеры этих файлов мы с вами видели выше. Они помимо той информации, которую мы уже обсудили, содержат еще много другой и очень важной: например, ссылку на собственно файл изображения, информацию о системе координат и ее единицах (совсем скоро мы приступим к обсуждению и этого вопроса) и т. д. А можно привязку хранить и внутри самого файла изображения, в тех самых метаданных, о которых речь шла в самом начале. Так например устроены файлы в формате geotiff [10], и если мы внимательно посмотрим на рисунок-скриншот с метаданными выше, то в самом начале этих метаданных легко найдем информацию, аналогичную приведенной в примере с world-файлом.
Изложенного, пожалуй вполне достаточно для понимания специфики тех форматов, с которыми нам в дальнейшем придется работать. В следующей части нашего теорминимума мы перейдем к подробному рассмотрению понятия координат и всего, что с этим понятием связано.
Примечания
1. Строго говоря, термин «пиксель» относится только лишь к изображению на экране, а не к содержимому файла. Однако очень часто, хотя и не совсем правильно, «пикселем» называют и единицу хранения растрового изображения, то есть «точку». Поэтому я буду употреблять как один, так и другой термин, если точное значение будет вполне понятно из контекста.
2. Другим примером метаданных является собственно размер изображения в пикселях (точках) отдельно по ширине и высоте. Вместе с разрешением эти размеры и определяют физический размер в линейных единицах при выводе, например, на печать.
3. Традиционно разрешение измеряется в количестве точек на дюйм и обозначается как dpi, dots per inch.
4. В далекие времена триумфа программы OziExplorer формат .ozf был изобретен именно в этих целях для имеющихся тогда мобильных устройств, которые имели намного меньший объем памяти и быстродействие по сравнению с современными. Поэтому обычные форматы они попросту «не тянули».
5. Внимательный читатель на рисунках приведенных выше, скорее всего, уже обнаружил записи вида «Тип данных: Byte — 8-битное беззнаковое целое» или «Точность: 8 бит, нелинейное целочисленное». Все дело в том, что растровые файлы позволяют хранить не только изображения, но и другие географические данные, например, модели высот местности. Для такого хранения нужна большая точность, нежели чем целые числа, поэтому каждая точка растра может быть описана, например, дробным значением «с плавающей запятой», и тогда мы можем отвести под хранение такого числа нужное количество байт в зависимости от требуемой точности. Но в нашем изложении такие специализированные растры нам не понадобятся, везде мы с вами будем иметь дело с целочисленными значениями.
6. С точки зрения классификации самого верхнего уровня (на «бинарные» и «текстовые») растровые и векторные форматы также различаются. Растровые форматы — всегда бинарные (двоичные). А вот векторные файлы могут быть и теми, и другими, и даже иметь специальный формат, как разновидность бинарного — файл базы данных. Но в приведенном примере для наглядности отображения использован широко распространенный текстовый формат — .geojson.
7. У каждой точки есть две координаты (например, широта и долгота), всего для двух точек получится четыре значения переменных, следовательно по двум точкам можно рассчитать четыре параметра, а по трем — целых шесть. Если забежать немного вперед, два параметра определят сдвиг в плоскости по двум осям координат, еще один — общий масштаб, и еще один — поворот, если он требуется. Если же у нас есть три точки, то в совокупности они дадут шесть величин координат и по ним можно дополнительно рассчитать еще три параметра: сделать масштабы по разным осям различными и добавить еще параметр «скошенности» прямоугольника в параллелограмм.
8. Так например, не раз упомянутый выше OziExplorer вообще не умел ничего делать с растром, кроме сдвига и масштабирования, для чего достаточно и двух точек. Возникает вопрос: а на что же «тратятся» избыточные точки привязки, зачем их берут в большем количестве и почему считается, что такая привязка точнее? Мы это увидим, когда будем самостоятельно привязывать растр, здесь же коротко скажу, что такой избыток тратится на вычисление погрешности привязки и ее оптимизацию с тем, чтобы сделать такую погрешность возможно меньшей. У более современных программ же совершенно другое поведение. Наименее предсказуемым образом ведет себя Global Mapper. В зависимости от количества точек привязки он будет выбирать все более сложные алгоритмы, в том числе и сильно нелинейные, что в случае большого количества точек и особенно в случае ошибок в присваивании им координат может приводить к совершенно катастрофическим нелинейным искажениям исходного растра. В то же время QGIS ведет себя более «щадящим растр» образом и всегда использует более линейные методы преобразования везде, где это возможно. Бороться с разной интерпретацией «поточечной привязки» разными программами невозможно, эти алгоритмы зашиты в самих программах, так что эти неприятные эффекты можно только учитывать при открытии растров с готовыми привязками в таких форматах.
9. Чуть позже мы с вами узнаем, что эти шесть параметров, о которых все время в этой части идет речь, определяют так называемое аффинное преобразование. Оставим пока это до подробного рассмотрения трансформаций при самостоятельной привязке.
10. Geotiff — это специальное расширение обычного формата .tiff, которое специально и предназначено для хранения дополнительной геоинформации, и в первую очередь, как раз информации о привязке.