Как создать свою ГИС с помощью GIS ToolKit Active

Урок 8. Функции для работы с растровыми изображениями

Автор: Дарья Лунченко

В прошлых уроках мы работали исключительно с векторными картами, но в ГИС очень широко применяются также и растровые данные. Отсканированные карты, аэрофотоснимки и спутниковые снимки служат источником данных для создания и редактирования векторных карт. В свою очередь результаты обработки векторных данных часто выдаются потребителю в виде растрового изображения. А раз растры так важны, то разберемся, как с ними работать.

В этом уроке мы рассмотрим несколько важных функций GIS ToolKit для работы с растровыми изображениями и добавим в наше ГИС-приложение свой собственный редактор растровых карт.

После прохождения этого урока наше приложение будет уметь:

  • импортировать графические изображения в формат растровой карты .rsw;
  • устанавливать текущий редактируемый растр;
  • устанавливать рамку растрового изображения;
  • осуществлять привязку растра по двум точкам;
  • оптимизировать растровую карту;
  • сохранять растровые данные в формат BMP, TIFF, RSW;
  • сохранять векторные данные в формат BMP, TIFF, RSW;
  • получать значение цвета любого пикселя растра;
  • перекрасить пиксели растра выбранным цветом.

Как будет выглядеть наше ГИС-приложение с добавленным редактором растров показано на рисунке ниже.

Рисунок 1 - Внешний вид приложения
 

Скачать рабочий образец программы, и ее исходный код можно на страничке "Дополнительные материалы к уроку 8". Если у вас не установлен GIS ToolKit Active, то для запуска приложения вам потребуется загрузить библиотеки GIS ToolKit, и выполнить их регистрацию. Все необходимые библиотеки и короткая инструкция размещены на этой же странице.

 

1. Добавление кнопок на панель инструментов

Для создания редактора растров, добавим на правую панель инструментов следующие кнопки: "Открыть растр", "Выбор текущего растра", "Установить рамку растра", "Привязка растра по двум точкам", "Оптимизировать растр", "Сохранить растр в BMP,TIFF,RSW", "Сохранить карту в BMP,TIFF,RSW", "Карандаш" (рис.2).

Рисунок 2 -Внешний вид панели инструментов редактора

 

2. Описание событий, соответствующих кнопкам на панели инструментов

2.1 Открыть растр

Данная функция позволит нам с помощью стандартного диалога ГИС "Панорама" (рис. 3) загрузить графическое изображение из форматов BMP, JPEG, PNG, TIFF и т.д. в растровый формат RSW. В диалоге загрузки вы сможете настроить путь создания нового файла, выбрать файл привязки растра при его наличии, а также просмотреть основные характеристики изображения.

Рисунок 3 - Диалог загрузки растровой карты
 

Для загрузки растровой карты:

  • создадим новый класс FRstEdit.cs, в который поместим все функции по редактированию растра;
  • при нажатии на кнопку "Открыть растр", создадим событие ButtonActionRswTool, в котором определяем функцию OpenRswFunc;
  • в классе FMapAPI импортируем функцию загрузки графического изображения в растровую карту DialogLoadImageToRsw;

  • в функции OpenRswFunc, вызываем диалог открытия данных OpenMapFileDialog, и с помощью свойства OpenMapDialog1.FileType, определяем категорию выбранного файла, если была выбрана растровая карта в формате .rsw, то открываем её или же добавляем к уже открытым данным;

  • если был выбран графический файл, то вызываем диалог загрузки графического изображения в растровую карту RSW, после чего отрываем или добавляем данные;

 

2.2 Выбор текущего растра

Так как пользователь может одновременно открыть несколько растровых изображений, при работе с функциями обработки растров существует необходимость выбора активного растра, для которого эти функции будут применяться. Данная операция позволит, выбрав растр из списка, сделать его доступным для редактирования (рис.4).

Рисунок 4 - Выбор текущего растра
 

Для реализации данной функции:

  • добавляем на форму из панели элементов стандартный компонент для отображения рамки и подписи вокруг элемента GroupBox, и помещаем в него компонент - раскрывающийся список ComboBox (рис.5);

Рисунок 5 - Вид диалога "Выбор текущего растра"
 

  • определяем функцию SetEditRswFunc, в которой при нажатии на кнопку "Выбор текущего растра", отображаем выпадающий список, заполненный с помощью функции RswComboBox.Items.Insert;

  • при изменении текущего растра в выпадающем списке, определяем выбранное поле RswComboBox.SelectedItem, и устанавливаем соответствующий номер растра;

 

2.3 Отображение растра по рамке

Для установки границ растрового изображения воспользуемся функцией отображения растра по рамке. Установление границ может понадобиться, к примеру, при создании единого растрового изображения из отдельных фрагментов. При ограничении рамкой, сам растр не изменяется, но на экране отображается только выбранный участок (рис.6).

Рисунок 6 - Установка рамки растра по заданному контуру
 

Реализация данной функции:

  • добавляем на форму из панели элементов стандартный компонент для отображения рамки и подписи вокруг элемента GroupBox, и помещаем три элемента CheckBox, для выбора условий ограничения рамкой;
  • в классе FMapAPI.cs импортируем функцию для создания временной пользовательской карты mapCreateAndAppendTempSite, она нам понадобится для правильной работы функции по установке рамки растра, его привязке, при условии, что не открыто ни одной векторной карты;
  • в функцию создания временной карты передаем идентификатор открытых данных, а также адрес классификатора карты, после чего вызываем ее при добавлении нового растра и при запуске приложения;

  • при выборе условия установить рамку по заданному контуру, пользователю предлагается растянуть прямоугольную область, в результате чего, после отжатия кнопки мыши установится рамка растра;
  • при выборе данного условия с помощью функции MapSelectRect1.StartAction, включаем режим выбора области;

  • определяем функцию MapSetRswBorderFunc и размещаем её в событии по отжатию кнопки мыши MapView1_OnMapMouseUp;
  • если произошёл выбор области, создаем пустой объект и устанавливаем его метрику (подробнее в уроке № 2, п.2.3);

  • используя функцию aiMapRsts.get_MapRsts, получаем доступ к растровой карте по порядковому номеру, к объекту растровой карты aiMapRst и его функции aiMapRst.SetRstBorder, устанавливаем рамку растра, по созданной ранее области;

  • при выборе условия "установить рамку по объекту карты" необходимо, чтобы одновременно с растрами была открыта и векторная карта. На этой карте пользователю нужно выбрать замкнутый объект, по которому будет установлена рамка;
  • для реализации данного условия включаем режим выбора объекта в заданной точке, и с помощью той же функции aiMapRst.SetRstBorder устанавливаем рамку;

  • для того, чтобы сбросить рамку отображения растра при нажатии на соответствующее условие, используем функцию MapAPI mapDeleteRstBorder;

 

2.4 Привязка растра по двум точкам

Привязка растровой карты проводится по векторной карте или по другому растру уже имеющему привязку, поэтому вначале необходимо открыть такой документ, после чего добавить в него привязываемый растр. Ниже мы рассмотрим три вида привязки: привязка по двум точкам с масштабированием, с непропорциональным масштабирование (размеры пикселя по X и по Y могут отличаться), с масштабированием и поворотом (рис. 7).

Рисунок 7 - Привязка растра с масштабированием и поворотом
 

  • Добавляем на форму из панели элементов стандартный компонент для отображения рамки и подписи вокруг элемента GroupBox, и помещаем три элемента CheckBox, для выбора условий привязки растра;
  • при выборе условия привязка растра по двум точкам с масштабированием, пользователю необходимо последовательно указать пары точек на растре и точек, в которые указанные точки должны переместиться, после чего производится параллельное перемещение растра с изменением его масштаба;
  • при выборе данного условия меняем вид курсора на перекрестие;

  • в классе FMapAPI импортируем функцию AttachRswWithScalingEx для привязки растра с масштабирование по двум точкам (устанавливается одинаковый размер пикселя по X и по Y);

  • определяем функцию SetRswAttach_MouseDown, в которой используя счетчик точек rstsnappoint, поочередно запоминаем пары точек растра и точки, в которые их необходимо переместить;

  • используя импортируемую функцию, осуществляем привязку растра, передавая в неё полученные координаты точек;

  • при выборе условия привязка растра по двум точкам с непропорциональным масштабированием, пользователю необходимо последовательно указать пары точек на растре и точек, в которые указанные точки должны переместиться, при этом размер пикселей растра по координатам X и Y могут отличаться;
  • в классе FMapAPI импортируем функцию AttachRswWithScaling для привязки растра с масштабирование по двум точкам;
  • далее проводим привязку по аналогии с привязкой растра по двум точкам с масштабированием;

  • при выборе условия привязка растра по двум точкам с поворотом и масштабированием, пользователю необходимо последовательно указать пары точек на растре и точек, в которые указанные точки должны переместиться, после чего производится параллельное перемещение всего растра с изменением его масштаба и ориентации;
  • в классе FMapAPI импортируем функцию AttachRswWithScalingAndRotation для привязки растра с поворотом и масштабированием;
  • одним из параметров данной функции является HMESSAGE handle - идентификатор окна диалога для обработки сообщений о ходе процесса, которые посылаются во время выполнения функции привязки, таким образом добавим на форму элемент для отображения процесса выполнения операции progressBar;
  • создадим обработчик оконных сообщений WndProc, в котором, используя метод Thread.Sleep, приостанавливаем текущий поток на 300 млс, для корректной прорисовки состояния progressBar;

  • аналогично с предыдущими пунктами, проводим привязку изображения с помощью функции AttachRswWithScalingAndRotation;

 

2.5 Оптимизировать растровое изображение

Данная функция позволяет проводить LZW, JPEG сжатие и декомпрессию растров, а также применяется после редактирования растровой карты, после многократных установок рамки растровой карты, при несовпадении изображения растра в разных масштабах отображения (рис.8).

Рисунок 8 - Диалог оптимизации растровой карты
 

Реализация:

  • в классе FMapAPI импортируем функцию LoadRstCompressDialog - диалог "Оптимизация растровой карты";

  • при нажатии на кнопку "Оптимизация растра" вызываем диалог оптимизации;

 

2.6 Сохранение векторных и растровых карт в форматы BMP, TIFF, RSW

Для сохранения выбранного фрагмента карты, растра, или же всей карты, растра в формате BMP,TIFF, RSW, выполняем следующие действия:

  • добавляем на форму из панели элементов стандартный компонент для отображения рамки и подписи вокруг элемента GroupBox, и помещаем два элемента CheckBox, для выбора режима сохранения (рис.9);

Рисунок 9 - Меню выбора режимов сохранения растровой и векторной карт
 

  • при выборе опции "сохранение растра по выбранной области", включаем режим выбора области на растре/карте;

  • добавляем на форму стандартный элемент SaveFileDialog, позволяющий выбрать директорию для сохранения файла;
  • в классе FMapAPI импортируем функцию LoadMapToPicture для сохранения карт/растров в формате BMP, TIFF, RSW, и функцию mapGetRstScale для запроса масштаба растра, масштаб карты определяем свойством MapView1.MapScale;

  • определяем функцию SaveRswMapToPicture, в которой при выборе опции "сохранения растра по выбранной области", устанавливаем координаты фрагмента сохраняемой карты;

  • вызываем диалог выбора директории для сохранения файла и, устанавливая разрешающую способность, количество бит на пиксель, масштаб, сохраняем выбранный участок карты/растра с помощью функции LoadMapToPicture;

  • при выборе опций "сохранение растра/карты по рамке растра/карты" происходит сохранение растра/карты по их габаритам;
  • для определения габаритов растра по его номеру, используем функцию MAPAPI mapGetActualRstFrame;

  • для определения габаритов карты, используем функцию aiMapSelect.GetDFrame;

  • далее аналогично с сохранением по выбранной области, сохраняем карту/растр с помощью функции LoadMapToPicture.

 

2.7 Получение значения пикселя растра

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

Начнем с получения значения в точке растра: научим наше приложение показывать нам значение цвета RGB в точке нахождения курсора (рис.9).

Для этого:

  • добавим на форме в элементе StatusStrip, который используем для отображения координат, и три toolStripStatusLabel для отображения цвета в формате RGB;
  • определяем функцию GetRswPointColor, в которой при условии, что курсор мыши не выходит за рамки растра, получаем значение цвета точки растра по ее координатам в метрах - aiMapRst.PlanePointColor_get, после чего выводим полученные значения в окно статуса.

 

2.8 Инструмент "Карандаш"

Чтобы разобраться, как произвести замену текущего значения цвета в данной точке на новое, создадим в нашем приложении инструмент "Карандаш". С помощью этого инструмента пользователь, выбрав предварительно цвет из палитры, может перекрасить любой пиксель растра или группу пикселей растра (рис.9).

Рисунок 9 - Инструмент "Карандаш"
 

  • добавляем на форму стандартный элемент - диалог выбора цвета ColorDialog и при нажатии на кнопку "Карандаш" вызываем его, запоминая выбранный цвет;

  • для того, чтобы отображать курсор в виде карандаша, импортируем функцию LoadCursorFromFile из библиотеки Windows API "User32.dll";

  • определяем функцию для отображения курсора в виде карандаша PaintCursor и вызываем ее в событии по передвижению мыши MapView1_OnMapMouseMove;

  • при рисовании необходимо указывать цвет пикселя в формате COLORREF, таким образом создадим функцию GetBGR, в которой преобразуем цвет из формата RGB в формат COLORREF;

  • определяем функцию SetRswPointColor_MouseUp, в которой получаем габариты растра, и перекрашиваем выбранный пиксель, после чего сохраняем изменения растра;

  • определяем функцию SetRswPointColor_MouseDblClick для завершения процесса рисования по двойному клику мыши;

 

В этом уроке мы научились примененять функции MAPAPI и GIS ToolKit Active для работы с обычными изображениями. В следующем уроке мы разберемся, как работать с еще одним типом растровых данных: с мультиспектральными спутниковыми снимками.

Смотреть: Дополнительные материалы к уроку 8