Идея спасти мир и при этом заработать немного шекелей витала у меня в голове уже давно. Имея неплохой накопленный опыт в области геоинформационных систем и защитивши в свое время диссертацию с их применением мне не хватало знаний разработчика. Окончив IT-курсы и получив доступ к «Святому Граалю знаний» я понял, – пора, и завертелось!
Летом 2024 года мы в составе команды «Arrow» одержали победу, заняв третье место в хакатоне «Лидеры цифровой трансформации» и вошли с нашим проектом в топ-100, став резидентами «Академии инноваторов» у нас появился свой стартапп.
Общая идея такова. Arrow - это платформа для анализа и обработки спутниковых снимков, использующая технологии машинного обучения и нейросетей для мониторинга окружающей среды, строительства и природопользования. Наш продукт помогает бизнесу и государственным структурам автоматизировать выявление экологических нарушений и незаконных построек, обеспечивая более точное и своевременное реагирование. Это в «розовом» будущем, а пока это только проект «Мобильное приложение для управления антропогенной нагрузкой на особо охраняемых природных территориях Камчатского края», занявшее призовое место, хотя и этот результат тоже когда-то был только в мечтах.
Я хочу открыть целый цикл статей в котором постараюсь осветить историю жизненного цикла нашего проекта «Arrow», которая будет писаться на ваших глазах. Здесь будет все: и фронт и бэк и мобильная разработка, будет и деплой в облако. В этих статьях, которые к стати буду писать не только я, но и ребята с моей команды, мы хотим осветить все начиная от создания MVP (минимально жизнеспособный продукт) и заканчивая выводом проекта в продакшн, анализ целевой аудитории и поиск первых клиентов, привлечение первых инвестиций, подбор команды, в общем все этапы через которые нам предстоит пройти для достижения своей цели, - получения интересного и востребованного продукта. Начнем же…
В современных реалиях блокировки доступа ко многим программным продуктам остро встает вопрос о переходе к использованию отечественных или, замещающих их и распространяемых открыто, ресурсам для построения элементов инфраструктуры пространственных данных.
Данная статья освещает практический подход для решения задачи построения Веб-ГИС приложения и сервисов на основе открытых ресурсов и на примере нашего проекта. Основное внимание в ней будет уделено созданию общей структуры проекта и освещению ресурсов на которых он функционирует.
Проект реализован с применением клиент-серверной архитектуры (рисунок 1). Серверная часть включает в себя СУБД для хранения векторных и растровых наборов данных, файловое хранилище растровых тайлов, сервер приложений Gunicorn, обслуживающий сам проект, и веб-сервер Nginx для взаимодействия, через протокол REST full с сервисами приложения, программ клиентов, которыми могут быть десктопные и (или) мобильные и (или) веб-браузеры. Таким образом, весь проект будет размещен в облаке Reg.ru о чем в дальнейшем будет отдельная статья, а пока мы работаем на нашей локальной машине (localhost), с организацией туннелированного доступа с применением Ngrok.

Технологический стек проекта включает в себя следующие свободно распространяемые ресурсы:
СУБД Postgresql с надстройкой PostGIS, которая предоставляет дополнительные возможности для работы с геопространственными данными, превращая базу данных в геореляционную;
Широко распространенный скриптовый язык программирования Python;
Не менее широко известный фреймворк, предназначенный для создания веб-приложений Django, взаимодействующий с СУБД с помощью технологии ORM (Object Relations Mapping). Эта технология позволяет работать с выбранной СУБД посредствам классов языка программирования, меняя лишь специальный драйвер, минуя при этом необходимость в написании SQL-запросов и, что самое главное, без изменения исходного программного кода приложения;
Для взаимодействия клиента с серверной частью предназначен Django REST фреймворк. DRF – одна из современных технологий создания API (программного интерфейса приложения), основным преимуществом которой является возможность организации совместной работы клиентских и серверных программ, написанных на различных языках программирования;
Библиотека GDAL содержит в себе полноценный функционал современных ГИС (геоинформационных систем) общего назначения, объединяя в себе две библиотеки – одноименную gdal, для работы с растровыми наборами данных и ogr, для работы с векторными форматами данных (shape, kml, geojson и др.). Активация этой библиотеки превращает фреймворк Django в GeoDjango;
- Для анализа спутниковых снимков (получаемых через API Sentinel Hub) применяются библиотеки Numpy и Pandas, дополнительно используется Jupiter Notebook, в том числе для работы со сверточной нейронной сетью U-Net для сегментации изображений;
Библиотека Leaflet (либо OpenLayer 3) посредствам java-скриптов и во взаимодействии с html-шаблонами и таблицами стилей CSS, визуализирует геоданные в окне веб-браузера и предоставляет пользователю элементы интерфейса для работы с серверным приложением;
В качестве карты-подложки применяется OSM-карта.
Создание проекта предполагает установку языка программирования, модуля для работы с виртуальными средами venv, пакетного менеджера pip, СУБД Postgrsql с расширением PostGIS, в качестве редактора кода я использую VSCode. В зависимости от операционной системы для установки всего этого добра используются различные менеджеры, например в MacOS это brew, в Ubuntu – apt, в Mandjaro pacman и т.д. Я работаю еще в Windows, но там использую стандартные .exe-шники. Тут и далее буду работать с Ubuntu, так как в дальнейшем при деплое на удаленном сервере Reg.ru тоже будет применяться этот дистрибутив Linux.
sudo apt install python3-venv python3-pip postgresql postgisДалее создается база данных от имени пользователя postgres. Переключаемся на этого пользователя и заходим в утилиту psql.
sudo su postgres
psqlALTER USER postgres WITH PASSWORD `admin`;Теперь создаем базу данных.
CREATE DATABASE test;Далее нужно активировать для этой базы данных расширение postgis. Подключаемся к базе.
\c testИ активируем расширение.
CREATE EXTENSION postgis;Со списком всех доступных расширений для работы с пространственными данными и для их активации рекомендую ознакомится со справкой на сайте PostGIS.
Выходим.
\qПереключаемся с пользователя «postgres» на пользователя операционной системы.
exitТеперь при создании полей в моделях базы данных нам, помимо стандартных типов данных, также будет доступно поля данных с типом «геометрия».
Следующим шагом нам необходимо создать виртуальное окружение для размещения в нем нашего проекта и установить в него необходимые зависимости, главные из которых фреймворки django и djangorest, а также драйвер для работы с базой данных Postgresql – psycopg2-binary.
mkdir geodjangoПереключаемся на эту папку, это будет наша рабочая директория.Создаем папку для размещения проекта.
cd geodjango Создаем окружение, где env – это названия окружения.
python –m venv envИ активируем его (для выхода из виртуального окружения необходимо запустить файл deactivate).
source env/bin/activateТеперь установим в виртуальное окружение необходимые для работы проекта зависимости. Список этих зависимостей содержится в файле requirements.txt.
pip install –r requirements.txtМожно проверить все ли необходимые зависимости установлены командой pip freeze (с их версиями).
Находясь в рабочей директории «geodjango», приступаем к созданию проекта и приложения в нем.
Создание проекта выполняется командой, где geodjango – это название проекта.
django-admin startproject geodjangoСоздание приложения выполняется командой, где geoapp – это названия приложения.
python manage.py startapp geoappПри создании проекта и приложения в нем с помощью фреймворка Django формируется первоначальная файловая структура. Каждый из этих файлов имеет свое строгое предназначение. Например, файл settings.py, в том числе, предназначен для подключения к предварительно созданной на основе шаблона PostGIS базе данных.
Для настройки подключения используется секция DATABASES.
DATABASES = {
'default': {
'ENGINE': 'django.contrib.gis.db.backends.postgis',
'NAME': 'test',
'USER': 'postgres',
'PASSWORD': 'admin',
'HOST': 'localhost',
'PORT': '5432',
}
}
Структура базы данных создается в файле models.py, где указываются необходимые модели (таблицы) с атрибутивными полями, хранящими данные определенных типов, а также поле для хранения геометрии пространственных объектов.
После создания моделей выполняется их миграция в базу данных и регистрация в файле admin.py для доступа к данным через специальную административную панель.
Каждое внесение изменений в модели базы данных требует создание миграций.
python manage.py makemigrationsКоманда ниже создает модели в базе данных.
python manage.py migrateДля взаимодействия с данными базы предназначен файл views.py. Он содержит функции и классы представлений, описывающих программную логику приложения.
Настройка взаимодействия клиента с этими представлениями осуществляется в результате процедуры роутинга – задания url-адресов доступа к тем или иным функциям, выполняемой в файле urls.py.
Функции генерируют контент, который рендерится в html-шаблоне, размещенном в папке templates, и визуализируется в окне веб-браузера с применением таблиц стилей CSS.
Если «обернуть» такие функции в специальный декоратор (или создать вместо функций классы наследующие атрибуты встроенных в Django классов джинериков и миксин, что является более современным подходом) они будут способны обрабатывать REST-запросы от клиента.
Такие запросы (или ответы на них) могут содержать тело данных, записываемых (или извлекаемых) в базу данных, через процедуры сериализации (преобразования объекта (словаря данных) в строку байтов для передачи по линиям связи), десериализации (обратно сериализации) и валидации (проверку данных на соответствие ожидаемой структуре).
Для понимания элементарный пример такого взаимодействия, реализованного в приложении, представлен ниже.
Пользователь выбирает элемент управления, размещенный в окне браузера. К этому элементу подключен java-скрипт формирования, например, некоторого условного POST-запроса.
// Добавляем маркер
function saveMarkerToDatabase(coordinates, markerName) {
fetch('https://swan-decent-shrew.ngrok-free.app/api/create_point/', {
// Задаем метод REST-запроса
method: 'POST',
// Формируем хедер запроса
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': getCookie('csrftoken'), // Добавляем CSRF-токен в заголовок запроса
},
// Формируем тело запроса
body: JSON.stringify({ name: markerName, location: 'SRID=4326;POINT(' + coordinates.lng + ' ' + coordinates.lat + ')' })
});
}В момент клика мыши по определенному url на сервер отправляется этот запрос, содержащий в своем теле контент: имя события и данные локации в формате WKT (код системы координат и проекции и координаты точки). Такой запрос, кроме тела, должен содержать служебную информацию в своем заголовке, защищающую приложение от внешних атак – CSRF-токен.
Связанная с этим url функция, ее еще называют эндпоинтом, успешно отрабатывает о чем свидетельствует статус ответа 200, если не возникают какие-либо исключения.
Возвращаемым результатом этой функции - представления будет некий контент. Это может быть файл формата GeoJSON, содержащий значения каким-то образом обработанные и записанные (извлеченные, обновленные, удаленные) в базу данных, а также, помещенные по определенным ключам в самом GeoJSON.
Например, по ключу «объекты» во вложенный список помещается геометрия объекта вместе с ее типом и, по ключу «свойства», - параметры атрибутов пространственных объектов, в данном примере это название инцидента.
{ "context_point_trek": { "type": "FeatureCollection", "crs": { "type": "name", "properties": { "name": "EPSG:4326" } },
"features": [
{ "type": "Feature", "id": 1, "properties": { "name": "Точка: 1" }, "geometry": { "type": "Point", "coordinates": [ 158.839538, 53.572238 ] } },
{ "type": "Feature", "id": 2, "properties": { "name": "Точка: 2" }, "geometry": { "type": "Point", "coordinates": [ 158.83972, 53.572024 ] } }, (и так далее...)
Такой контент в виде переменных передается обратно в html-шаблон, где обрабатывается уже посредствам java-скриптов и стилизованно отображается в окне веб-браузера в виде слоев карты, таблиц, графиков, диаграмм и т.д., совместно с элементами пользовательского интерфейса (рисунок 3). Также такой контент может отдаваться в теле ответа на сформированный POST-запрос, для этого нужно лишь подкорректировать эндпоинт.

Для администрирования приложения, предназначается специальная панель Django, позволяющая создавать и удалять записи из базы данных пользователям, прошедшим процедуры идентификации и аутентификации (рисунок 4).

Для создания пользователя (на начальном этапе) используется команда
python manage.py createsuperuserВ дальнейшем, для регистрации новых пользователей приложения, этот функционал будет расширен.
Подытожить материал этой статьи хочется следующим. Логика веб-ГИС-приложения будет реализовывать инструменты получения спутниковых снимков с открытых ресурсов, например Sentinel Hub, и обработки полученных растров по специальным алгоритмам. Суть этой обработки заключается в комбинировании спектральных каналов спутниковых снимков и расчет спектральных индексов для решения задач на основе технологий машинного обучения: дешифрирования, классификации и кластеризации объектов и явлений местности. В дальнейшем также планируется внедрить в проект на основе этих наработок предобученные нейронные сети. Само собой это материалы для написания еще нескольких статей в дальнейшем. Будьте на связи, кому интересно подписывайтесь.
В общем такой подход позволит реализовать ряд сервисов, размещенных в облаке, доступ к которым будет осуществляться по подписке. Клиенты будут использовать такие сервисы для конструирования собственных приложений, на подобии Notion.

Также планируется, возможность организации целой инфраструктуры (как вы наверно уже поняли, в минимально работоспособном варианте это уже реализовано), когда на основе сервисов можно будет создавать панели мониторинга, например мест скопления твердых бытовых отходов, незаконных застроек, зон пожаров и гарей, затоплений и многого другого. Такие дашборды смогут конструировать сами пользователи на основе предварительно созданного инструментария на стороне фронта (карт, таблиц, графиков, диаграмм и др.). Своего рода nocode-приложения для неподготовленных пользователей, либо с элементами кодирования, для более подготовленных, путем использования нашего API. Кроме того, мы сами сможем обеспечить всю цепочку создания, развертывания и поддержки приложения под более конкретные запросы пользователей.
Еще одним элементом этой инфраструктуры, станет возможность не только мониторить обстановку, но и отдавать распоряжения и контролировать их исполнение различным службам реагирования (рисунок 5), путем реализации дополнительного связанного с базой данных мобильного приложения (Android, IOS, и др. наше приложение платформонезависимо, в этом его прелесть!).
Видеопрезентация полного цикла работы приложения доступна по ссылке.
