/3dvizGradle

Primary LanguageJavaScript

Разворот сайта

  • Использовал как базу Google cloud. Там при регистрации дают стартовые 300$ для демонстрации системы.
  • для сборки и тестирования есть набор шелл скриптов в корне проекта. Это является отправной точкой для работы с проектом:
    • debug.sh - делает сборку и запускает проект локально в режиме отладки, понятном для idea
    • test.sh - делает сборку и запускает проект локально (по дефолту порт 4567)
    • Далее идут 2 скрипта которые имеют одинаковую логику. делают сборку, собирают докер контейнер, публикуют в Dockerhub. Но в разных форматах:
      • withDataBuild.sh - публекует вместе с данными. Публикуется с тегом withData.
      • withoutDataBuild.sh - публикует без данных. Добавляет точку монтирования вольюма, куда можно приатачить внешний вольюм с данными через volume bind. Публикуется с тегом withoutData.
  • Для сборки джава артефактов используется инструмент Gradle. Инструкцию по основным методом можно прочитать здесь Для него ключевые файлы, из которых он будет делать сборку:
    • build.gradle - основной файл сборки. Здесь указаны все зависимости и логика сборки.
    • gradle.properties - файл собержит, различные переменные, которые могут понадобится градлу для сборки.
    • settings.gradle - содержит тех. информацию, например о имени пакета, версии, или логин/пароль, если артефакты куда-то публикуются
  • после публикации на докерхабе, можно создать kubernates проект в google cloud. Наиболее близкую инструкцию можно найти здесь Если использовать вариант, когда данные снаружи и аттачатся через вольюм, то вот инструкция, как это можно сделать
  • Пример развернутого приложения 35.239.213.226

Backend

Некоторые особенности

  • За основу REST-сервиса была взята библиотека Spark. Процессинг изображений реализован с помощью opencv 3.4 (opencv javadoc) Работа с файлами формата hdf5 использовалась библиотека jhdf5 (javadoc)
  • Для всех запросов идет gzip архивирование
  • Для всех запросов был добавлен хедер ("Access-Control-Allow-Origin": "*") чтобы можно было тестировать локалоно фронтенд отдельно от бекенда. Не был вынесен отдельно в пост шаг, а проставлен в каждом ресту, тк проставлялся не у всех запросов
  • Был добавлено ограничение по количеству одновременных запросов на особо тяжелые методы, тк система сильно подвисала, от вызова одновременно нескольких рестов
  • hdf5 и набор имеджей конвертируются в универсальный объект, описаный в интерфейсе IMatDatasetObject
  • Реализована работа только для массивов float, тк он использовался в работе. Если нужны какие-то другие типы, нужно наследоваться от класса H5Object. Сделать как-то универсально и красиво через дженерики не получилось из-за особенности библиотки jhdf5, где для каждого типа свои классы
  • Для работы с массивами, по максимуму применяются джава стримы, тк они оказались быстрее перебора циклом
  • В com.rbtm.reconstruction.DataObjects.NDArray реализована обертка для работы с многомерными массивами, тк стандартной реализации для джавы нет
  • Так же как и нет каких-то базовых вещей, типа нахождения минимума/максимума. Это реализовано в классе com.rbtm.reconstruction.Utils:CustomArrayUtils

Описание основных пакетов и классов

  • com.rbtm.reconstruction:Constants - все константы, включая различные пути. Описаны в самом файле
  • com.rbtm.reconstruction.Utils - различные полезные классы
  • com.rbtm.reconstruction.Utils:Timer удобно использовать, если нужно засечь время на определенном участке
  • com.rbtm.reconstruction:Main - описание всех рест запросов, REST API ниже
  • com.rbtm.reconstruction:WebAppHealper - вспомгательный класс для обработки рест запросов. Реализуют логику обработки запросов
  • com.rbtm.reconstruction.Converters - собраны конвертеры датасетов между форматами. Реализованы
    • hdf5 файл -> набор png изображений
    • hdf5 файл -> набор Mat
    • набор png изображений -> obj файл
  • com.rbtm.reconstruction.DataProcessing - классы по обработке изображений
  • com.rbtm.reconstruction.DataProcessing.Circle - классы для построения диаграммы по интегрированию колец
  • com.rbtm.reconstruction.MarchingCubes - Классы по алгоритму марширующих кубов

REST API:

  • GET /objects/all/

    • Описание: Возращает список всех объектов доступных для исследования
    • Тело запроса: -
    • Возр. тип: json
    • Комментарий: парсит список фалов, в дирестории OBJ_PATH, указаной в константах'
  • GET /objects/all/current/

    • Описание: Возвращает имя объекта, который выбран на данный момент
    • Тело запроса: -
    • Возр. Тип: text
    • Тело ответа: Имя объекта, выбраного последним. По дефолту возращает ""
  • POST /objects/all/current/

    • Описание: Выбрать новый объект для исследования
    • Тело запроса: {"objName": String }
    • Возр. Тип: text
    • Тело ответа: если операция выполнена успешно вернется имя объекта, если такого объекта нет, вернется “Fail”
    • Комментарий: после того, как выбран объект идет проверка, есть ли конвертированная модель в png формат, Если такой нет, то запускается конвертация hdf5->png array. Это позволило очень сильно сократить выполнение некоторых операций.
  • POST /objects/all/current/forceInit/

    • Описание: запускает конвертацию hdf5->png array.
    • Тело запроса: -
    • Возр. Тип: text
    • Тело ответа: строка Success при успехе и Fail, если произошел сбой.
    • Комментарий: операция нужна, если мы не уверены в консистентности данных (например повреждение буфера или искажение данных в нем) и требуется переконвертация
  • GET /objects/all/current/shape/

    • Описание: возвращает размеры объекта, который выбран на данный момент
    • Тело запроса: -
    • Возр. Тип: json
    • Тело ответа: {num: int, heigth: int, width: int}
    • Комментарий:
  • POST /objects/all/current/slice/filters/

    • Описание: задает фильтры в формате json массива
    • Тело запроса: [{имя_филтра: значение_филтра}, ...]
    • Возр. Тип: text
    • Тело ответа: Возвращает Success при успехе и Fail, если произошел сбой
    • Комментарий: порядок в пересылаемом массиве важен
  • GET /objects/all/current/slice/:id/

    • Описание: возвращает срез с номером id и заданными фильтрами в формате png
    • Тело запроса:
    • Возр. Тип: binary
    • Тело ответа: бинарный файл с картинкой в формате png
  • GET /objects/all/current/slice/:id/circleDiagram/

    • Описание: Возвращает данные для построения диаграммы интегрирования окружностей для среза с номером id и заданными фильтрами
    • Тело запроса: -
    • Возр. Тип: json
    • Тело ответа: {radius: int, value: float}, ...]
    • Комментарий: если нет подсчитанной диаграммы для текущих значений, делается подсчет и записывается в буфер, иначе возвращается диаграмма из буфера.
  • GET /objects/all/current/objFile/

    • Описание: Возвращает 3d объект в формате .obj
    • Тело запроса: -
    • Возр. Тип: text
    • Тело ответа: Текст с описанием модели в формате obj
    • Комментарий: Это оказалась достаточно тяжелая операция, тк размер файла может достигать 100-150мб. Браузер кидает ООМ

Frontend

Для css-шаблонов используется библиотека bulma.io У нее достаточно понятная и простая документация и есть все необходимое для данной задачи. Интерфейс выглядит следующим образом:

пример

Его можно разделить на следующие елементы:

  • Строка выбора - здесь можно можно выбрать объект для исследования, тип визуализации. Так же здесь отображается имя объекта, который иследуется в данный момент. Сейчас доступны следующие вкладки:
    • Welcome - где отображается данный текст
    • Slice - послойная визуализация
    • Surfaces - визуализция с помощью изоповерхностей
  • Окно визуализации - область визулаизации, которая делится на 2 части:
    • Область визуализации - область где непосредственно происходит визуализация
    • Панель нстроек - настройки и елементы управления, для каждого типа визуализации свои настройки

Для визуализации сладов реализована возможность накладывания произвольного набора фильтров. Все минимальные-максимальные значения привязаны к размеру изображения и присваиваются в файле filterGenerator. Порядок фильров имеет значение, могут повторяться. Посылается на сервер в json формате, при каждом изменении слоя иди фильтра Не было реализовано блокирования опций, если не выбран объект. Поэтому при изменении параметров автоматически выбирается первый в списке

Описание скриптов

Все скрипты вынесены в одно место, в конец index.html Порядок фалов важен

3party библиотеки

  • 3party-scripts/Three.js - библиотека three.js
  • 3party-scripts/OBJLoader.js - загрузка obj файлов
  • 3party-scripts/OrbitControl.js - управление камерой в three.js сцене
  • canvasjs - для построения графиков. Был вариант с d3.js но показалось силишком громозким решением для построения одного графика

вспомогательные скрипты

  • scripts/globalVars.js - глобальные переменные
  • scripts/networkHelper.js - функция для ajax запросов

основные скрипты

  • scripts/threeJsManipulations.js - все что связано с three.js:

    • создание и рендеринг сцены
    • добавление управления камерой
    • загрузка obj файла
    • логика кнопок управления
    • удаление сцены (TODO: после удаления все равно блокируется все остальное, нужно перезагружать страницу)
  • scripts/chartViz.js - создание графика (x - радиус, y - относительная сумма по кольцу)

  • scripts/imgSliceUpdater.js - Скрипт для для обновления среза.

    • Отпрвлет серверу список фильтров
    • Обновляет изображение среза
    • Высчитывает новые параметры изображения
    • Вызывает метод построения графиков из chartViz. Использует библиотеку canvasjs
  • scripts/objectListUploader.js - выгружает с сервера список доступных объектов для исследования. Запускается один раз на загрузке страницы. Полученый список генерирует в выпадающее меню в строке выбора

  • scripts/filterGenerator.js - скрипт который генерирует новый фильтр. Создает новый елемент списка со следующими полями:

    • Имя
    • Мин. значение
    • Слайдер
    • Текущее значение( в SliderUi.js описана логика как текущее значение становится интерактивной)
    • Макс. значение
    • Кнопка удаления фильтра

    Генерируется случайный id и присваевается каждому этому элементу в виде Имя_фильтра-id. Это нужно для того чтобы:

    • Находить все элементы при удалении
    • Для возможности хранить не уникальные имена фильтров, если мы накладываем несколько с одинаковым именем
  • scripts/index.js - скрипт, запускающийся на старте страницы:

    • Делает активными все падающие меню.
    • Проставляет необходимые действия всем кнопкам
    • Запускает objectListUploader.
  • scripts/sliderUi.js - скрипт необходимый чтобы все слайдеры были интерактивными