Данный проект представляет собой гибкий конфигурируемый инструмент для совмещения трехмерных изображений.
В основе инструмента лежит использование открытой библиотеки SITK для поиска преобразования, приводящего два 3D изображения в общие координаты.
Инструмент также позволяет применять найденное преобразование, сохранять преобразованные объемы в общих координатах как набор мультиканальных двумерных изображений, задавать начальное приближение в виде матрицы или интерактивным выделением особых точек и выполнять оценку качества совмещения в случае известного идеального преобразования.
Репозиторий содержит также пример структуры папок для работы с данными, тестовые данные, инструкцию по использованию и запуску инструмента на тестовом примере для Windows 10.
Для ОС Arch Linux.
Работа инструмента совмещения так же возможна на операционной системе Arch Linux и подобных ей.Важно! В случае Arch Linux можно использовать данную инструкцию, отличие присутствует только в команде активации виртуального окружения для терминала (пункт 2).
Для настройки виртуального окружения необходимо проделать следующие шаги:
-
Необходимо клонировать репозиторий или отдельно скачать файл
required_libraries.txtиз папкиrunnerрепозитория. -
Создать чистое виртуальное окружение с помощью virtualenv:
python -m venv venv_nameТакже можно воспользоваться conda .
- Активировать окружение:
path\to\venv_name\Scripts\activate.batДля ОС Arch Linux.
path\to\venv_name\bin\activate- Запустить в терминале из папки с файлом
required_libraries.txtкоманду
pip install -r required_libraries.txtДля работы с инструментом рекомендуется создать структуру папок и файлов следующего вида (пример такой структуры представлен в репозитории, поэтому его можно клонировать и использовать после настройки конфигов):
runnerexperiment_runner.pymetrics.pyparser.pyregistration_gui.pyrequired_libraries.txtresults_visualization.pysample_creator.pySITK.py
experimentsexample_algorithms_configssitk_config.jsontest_experiment_config_0.jsontest_experiment_config_1.json
test_datadata1...
data2...
...
Важно! В папке runner (может иметь любое название) обязательно должны содержатся все файлы c исходным кодом для запуска совмещения, а также файл required_libraries.txt с необходимыми библиотеками.
Папка experiments (может иметь любое название) - это папка, содержащая результаты экспериментов по совмещению. Все эксперименты рекомендуется делать в основной папке experiments, но можно и каждый раз указывать путь до произвольной папки. В выбранной пользователем директории при каждом запуске эксперимента алгоритм автоматически создает папку с заданным пользователем названием эксперимента и сохраняет в нее результаты, копии всех конфигурационных файлов, необходимых для точного повторения эксперимента, и временные файлы, создаваемые в процессе работы алгоритма.
Также в приведенном в репозитории примере в папке experiments есть папка example_algorithms_configs (может иметь любое название), содержащая примеры конфига метода SITK и конфигов экспериментов. Конфигов метода может быть сколько угодно - для каждого эксперимента может быть свой, либо же один конфиг метода может использоваться для нескольких экспериментов. Расположение конфигов методов указывается в конфиге эксперимента, а расположение конфига эксперимента указывается пользователем при запуске инструмента совмещения. При запуске каждого нового эксперимента копии указанных конфига метода и конфига эксперимента сохраняются вместе с результатами, что позволяет редактировать один и тот же конфигурационный файл и использовать его для разных экспериментов без потери информации о конфигурации предыдущих. Поэтому конфиги могут иметь любое расположение, но для удобства папка example_algorithms_configs с ними добавлена в experiments.
В репозитории содержатся тестовые данные, конфиги, результат работы инструмента совмещения. Ниже будет представлено объяснение процедуры настройки и запуска на примере структуры папок и данных в репозитории.
Для начала необходимо выкачать или клонировать данный репозиторий.
Для запуска тестовых примеров необходимо распаковать тестовые данные, содержащие реконструкцию грецкого ореха по слоям в изображениях формата .tif, и удалить архивы.
В репозитории представлено два эксперимента с парами данных в первом nut и nut_rotated (повернутый nut) и во втором nut и nut_enlarged (увеличенный в 1.5 раза nut).
Для запуска примеров необходимо настроить конфиги экспериментов.
Описание параметров конфига эксперимента.
{ "path_to_results_inf" : "Путь до папки, в которой автоматически будет создана директория с данными, полученными в результате работы алгоритма (experiments в репозитории).",
"path_to_results" : "/path/to/experiments/",
"experiment_name_info" : ["Для каждого эксперимента создается папка с его названием, взятым из поля experiment_name. Туда во время запуска алгоритма автоматически копируется текущий конфиг эксперимента и конфиг алгоритма с пометкой времени запуска. Так же в эту папку будут записаны все данные, полученные в результате работы алгоритма.",
"Если в папке path_to_results уже существует папка с названием experiment_name, то при новом запуске с тем же самым experiment_name алгоритм автоматически создаст папку с именем experiment_name_001, затем experiment_name_002 и так далее"],
"experiment_name" : "test_example_0",
"algorithm_name_info" : "Задает название папки, НЕ МЕТОД, метод задается исполняемым файлом и конфигом с настройками.",
"algorithm_name" : "sitk",
"algorithm_name_examples" : {
"1" : "sitk",
"2" : "sith",
"3" : "any_convenient_name_for_the_method"
},
"algorithm_execution_parameters_path_info" : "Путь до конфига метода, может иметь любое расположение и название.",
"algorithm_execution_parameters_path" : "/path/to/experiments/example_algorithms_configs/sitk_config.json",
"algorithm_executable_path_info" : "Путь до скрипта с методом.",
"algorithm_executable_path" : "/path/to/runner/SITK.py",
"alg_interpreter_path_info" : "Путь до файла python.exe вашего окружения.",
"alg_interpreter_path" : "/path/to/venv_name/Scripts/python.exe",
"VolumeLoadingMode_info" : "Не изменять.",
"VolumeLoadingMode" : "TwoVolumes",
"registered_volumes_writing_info" : ["Флаг для сохранения результата совмещения.",
"Если указать false, то полученные в результате совмещения объёмы не будут отписываться в тифы, записанными останутся только параметры найденного преобразования (его прямая и обратная матрицы)."],
"registered_volumes_writing" : true,
"minimize_padding_info" : ["Флаг для выбора области интереса при сохранении результата совмещения.",
"Если указать false, то полученные в результате совмещения объёмы будут представлять описанный прямоугольный параллелепипед вокруг результирующего совмещения целевого и изменяемого объёмов (логическое объеденение объёмов). В таком случае добавленные воксели без соответствующих значений интенсивностей в исходных объёмах будут иметь 0 значения интенсивности.",
"Если указать true, то то полученные в результате совмещения объёмы будут отображать пересечение результирующего совмещения целевого и изменяемого объёмов с областью целевого объёма"],
"minimize_padding" : true,
"calculate_metrics_info" : "Флаг для вычисления метрик - для вычисления значения всех предложенных метрик, кроме MSE, нужно указать эталонное преобразование в поле ниже",
"calculate_metrics" : false,
"path_to_gt_matrix_json_info" : "Путь до json файла с матрицей эталонного преобразования (примеры есть в репозитории в nut_rotated.rar и в nut_enlarged.rar).",
"path_to_gt_matrix_json" : "",
"SelectedVisualizedMetricsList_info" : "Метрики, которые будут рассчитываться, если включен флаг calculate_metrics. Можно исключить из списка ненужные и оставить только необходимые.",
"SelectedMetricsList" : ["MSE",
"normalized maximum deviation of distances (from geometry MSE)",
"maximum deviation of distances (from geometry MSE)",
"norm_geometry_rmse",
"geometry_rmse",
"norm_geometry_MSE"],
"path_to_markup_info" : "Путь до целевого объема, к которому будет приводится объем moving, может иметь любое расположение.",
"path_to_markup" : "/path/to/experiments/test_data/nut/",
"path_to_moving_info" : "Путь до изменяемого объема, преобразуемый для приведения в координаты целевого объёма markup, может иметь любое расположение.",
"path_to_moving" : "/path/to/experiments/test_data/nut_rotated/",
"path_to_initial_transform_matrix_json_info" : ["Путь до .json с начальным преобразованием, которое будет доуточняться методом (преобразование из moving в markup).",
"Пример json'a с нач. преобразованием содержится в папке тестового объема nut_rotated."],
"path_to_initial_transform_matrix_json" : "/path/to/experiments/test_data/nut_rotated/initial_matrix.json"
}Для запуска тестового примера настройку конфига метода производить не надо, описание полей конфига метода будет ниже.
Важно! Для использования матрицы начального преобразования, записанного в initial_matrix.json, в конфиге метода sitk_config.json в поле InitialTransform необходимо указать значение MATRIX.
После скачивания репозитория, настройки окружения, распаковки архивов в папке test_data и настройки конфигов экспериментов можно запустить тестовые эксперименты.
Из папки runner в консоли запустите эксперимент №0 (предварительно в конфиге метода sitk_config.json в поле InitialTransform необходимо указать значение MOMENTS, а InitialTransformViewer - false)
python experiment_runner.py /path/to/experiments/example_algorithms_configs/test_experiment_config_0.jsonАналогично, эксперимент №1 (предварительно в конфиге метода sitk_config.json в поле InitialTransform необходимо указать значение MATRIX, а InitialTransformViewer - true)
python experiment_runner.py /path/to/experiments/example_algorithms_configs/test_experiment_config_1.jsonПосле завершения работы алгоритма в выбранной в конфиге эксперимента папке для сохранения результатов (в тестовых конфигах это папка experiments) будет создана папка с названием эксперимента (в случае использования тестовых конфигов это папка test_example_0 и test_example_1 для тестовых экспериментов №0 и №1 соответственно). В ней будут созданы: папка processing с промежуточными файлами, необходимыми методу, папка sitk_ГГГГ_ММ_ДД_ЧЧ_ММ_СС_configs с копиями конфигов эксперимента и метода, папка stitching_results, в которой сохранятся основные результаты совмещения: padded_markup_0 и padded_test_0 это объемы одинакового размера, приведенные к одному масштабу, ориентации, смещению; colored_joining_volume_0 - исходное и преобразованное изображения записаные в R и GB каналах RGB изображения соответственно для демонстрации различий; папка metrics, в которой находятся: matrices.json с прямой и обратной матрицами преобразования между объёмами, time_mem.json, содержащий информацию о времени выполнения алгоритма и затраченном максимальном количестве оперативной памяти, metrics.json, содержащий рассичтанные по результатам совмещения выбранные пользователем в конфигурационном файле метрики качества совмещения (если рассчёт метрик отключен соответствующим флагом в конфигурационном файле, но этот json отсутствует) и папка graphs, содержащая данные о положении оптимизатора (значения параметров оптимизируемого преобразования) на каждой итерации в процессе работы алгоритма.
Основной результат эксперимента - это объемы в папках padded_markup_0 и padded_test_0 - их наложение позволяет получить совмещенный совместный объем, причем сделать это можно повоксельно - объемы специально приведены к одинаковым размерам.
Пример структуры папок с результатами тестового совмещения №0.
test_example_0processingsitkcustom_markupalg_out_json.json
sitk_ГГГГ_ММ_ДД_ЧЧ_ММ_СС_configstest_experiment_config_0.jsonsitk_config.json
stitching_resultssitkcustom_markupcolored_joining_volume_0metrics0graphs...
matrices.jsonmetrics.jsontime_mem.json
padded_markup_0padded_test_0test_transformed_0
В начале необходимо выбрать класс пространственного преобразования, которое будет искать алгоритм SITK для совмещения исходных объёмов. Это позволяет ограничить степени свободы при оптимизации параметров преобразования алгоритмом.
В текущей версии реализован поиск преобразования подобия и аффинного преобразования:
Similarity- преобразование подобия с 7 степенями свободы: 1 степень свободы при изотропном масштабировании по всем трём направлениям, 3 вращательные степени свободы и 3 степени свободы при параллельном переносе;Affine- аффинное преобразование с 12 степенями свободы: 3 степени свободы при анизотропном масштабировании, 3 вращательные степени свободы, 3 сдвиговых степени свободы и 3 степени свободы при параллельном переносе;
"TransformType": "Similarity"Одним из самых важных аспектов в работе SITK является начальное преобразование, которое данный метод будет уточнять в процессе работы.
Есть несколько доступных режимов работы по поиску начального преобразования:
GEOMETRY- геометрический центр одного трехмерного изображения приводится к геометрическому центру другого изображения, только преобразование смещения;MOMENTS- центр масс одного трехмерного изображения приводится к центру масс другого изображения, только преобразование смещения;POINTS- режим на основе ручной разметки особых точек;MATRIX- начальное преобразование из объемаmovingвmarkupзадается матрицей4x4в файле .json, этот способ был описан в предыдущем разделеРабота с прогонщиком;MANUAL- ручная тонкая настройка преобразования в конфиге, позволяет отдельно задать масштаб, вращение (в порядкеxyz), смещение (в порядкеxyz), причем смещение задается либо вручную отдельно по каждой координате (режимMANUAL), либо с помощью описанных выше режимовGEOMETRYиMOMENTS.
"InitialTransform": "MOMENTS",
"initial_transform_help": {
"possible_options" : ["GEOMETRY", "MOMENTS", "POINTS", "MATRIX", "MANUAL"]
},
"note" : ["Здесь фигурирует два разных значения MANUAL:",
"одно относится к полю InitialTransform выше и задает ручной режим определения начального преобразования SITK,",
"другое относится к полю InitialTranslationOption ниже - одно из полей настройки режима InitialTransform == MANUAL:",
"автоматическое совмещение центров объемов (GEOMETRY),",
"совмещение центров масс(MOMENTS)",
"или же ручное задание 3 координат смещения (MANUAL)."],
"InitialTransformParams":{
"info" : "при выборе InitialTransform == MANUAL параметры начального преобразования извлекаются из этого словаря.",
"scale": 1.0,
"rotation": [0.0 , 0.0, 0.0],
"InitialTranslationOption": "GEOMETRY",
"InitialTranslationOptionHelp":{
"possible_options" : ["GEOMETRY", "MOMENTS", "MANUAL"]
},
"translation_info" : "Задействуется только если InitialTranslationOption = MANUAL.",
"translation": [0, 0, 0]
},
"imagej_landmark_coords_file_path_info" : ["Используется в режиме POINTS.",
"У ImageJ есть плагин: plugins/registration/3d landmarks,",
"позволяющий с помощью GUI для двух объемов создать текстовый файл,",
"содержащий списки координат соответствующих точек в 2 объемах.",
"Здесь указывается путь до файла такого типа, который автоматически парсится,",
"и на основе этих координат производится начальное преобразование при совмещении"],
"imagej_landmark_coords_file_path" : "",Первые два режима сразу встроены в SITK, другие интегрируются в его работу после некоторой обработки.
Рекомендации:
- если ваши совмещаемые объемы слабо отличаются ориентацией (отличие не более 30 градусов), то лучше использовать
MOMENTS; - режим
GEOMETRYнельзя использовать, если объемы сильно отличаются ориентацией, например, если границы объекта в первом объеме в пределах 0-100 пикселей по одной из осей, а границы второго объема в пределах 500-600 пикселей, метод совместит центры изображений, но объекты в них могут не пересечься и метод даст некорректный результат, в целом лучше его никогда не использовать; - метод
POINTSвозможно один из лучших режимов на сложных данных, требует дополнительное ПО для разметки особых точек; - режим
MATRIXудобен, если начальное преобразование ищется в таком ПО как, например, 3D Slicer - здесь есть возможность получить начальное преобразование сразу в виде матрицы.
Начальное преобразование инициализируется на основе найденных соответствий между точками на двух изображениях. В качестве инструмента для разметки (разметчика) используется Fiji - расширенный дистрибутив ImageJ.
После запуска разметчика открывается основное окно

До начала разметки необходимо загрузить объемы, между которыми производится поиск начального преобразования: File->Import->Image Sequence->Browse->Указать путь до папки с объемом->OK.
В результате откроются два отдельных окна со срезами загруженных объемов

Далее необходимо открыть окно разметчика: Plugins->Registration->Manual landmark selection (3d)->В открывшемся окне указать в качестве First image объем markup, Second image - moving->OK.
После этого откроется окно, в котором будет содержаться информация о размеченных особых точках.
Разметка точек делается в окнах с загруженными объемами: двойным кликом необходимо выбрать какую-либо особую точку (угол объекта, граница и т.п.) на срезе первого объема, а затем эту же особую точку на срезе второго объема.
Ограничений на количество точек нет, но чем больше их будет, тем точнее будет итоговое начальное преобразование.

Информация о размеченных точка будет автоматически заноситься в соотвутстующее окно

После того как разметка будет закончена необходимо сохранить файл с разметкой нажатием Save (этот файл не имеет формат, для просмотра можно использовать Notepad++).
Для использования этого режима необходимо в файле конфига метода установить параметру InitialTransform значение POINTS, а также указать параметру imagej_landmark_coords_file_path в качестве значения путь до файла с разметкой.
"InitialTransformViewer_info" : ["Если true, включает просмотр результата совмещения начальным",
"преобразованием в режиме лоскутного наложения."],
"InitialTransformViewer" : false,
"Metric_info" : ["Тип используемой для итеративного совмещения метрики из набора метрик SITK",
"На данный момент реализована мультимодальная метрика совместной информации."],
"Metric" : "MattesMutualInformation",
"MMI_MetricNumberOfHistogramBins_info" : "Количество бинов в гистограмме для расчета метрики совместной информации.",
"MMI_MetricNumberOfHistogramBins" : 80,
"Interpolator_info" : "Тип интерполятора.",
"Interpolator" : "Linear",
"HistMatching_info" : ["True - выравнивание изображений по интенсивности с сохранением распределения",
"для корректной работы метрики совместной информации."],
"HistMatching" : true,
"MetricSamplingStrategy_info" : ["Способ отбора вокселей для рассчета метрики.",
"RegularGrid - равномерная сетка по всему объему;",
"Random - в случайном порядке."],
"MetricSamplingStrategy" : "RegularGrid",
"Optimizer_info" : ["Тип оптимизатора из набора оптимизаторов в классе registration method из библиотеки SITK.",
"На текущий момент доступно два оптимизатора RegularStepGradientDescent и GradientDescent."],
"Optimizer" : "RegularStepGradientDescent",
"Estimate_learning_rate_option_info" : ["Определяет, когда оптимизатор самостоятельно рассчитывает LearningRate:",
"Never - при оптимизации всегда используется заданный ниже размер шага оптимизации;",
"Once - размер шага рассчитывается автоматически один раз при переходе на новый уровень сжатия изображения;",
"EachIteration - величина шага рассчитывается на каждой итерации."],
"Estimate_learning_rate_option" : "Once",
"LearningRate_info" : "Величина шага оптимизатора.",
"LearningRate" : 2.0,
"NumberOfIterations_info" : "Ограничитель количества итераций на одном уровне сжатия изображения.",
"NumberOfIterations" : 150,
"minStep_info" : ["Только для оптимизатора RegularstepGradientDescent.",
"Останавливает оптимизацию на текущем уровне сжатия",
"при достижении указанного минимума для размера шага оптимизатора."],
"minStep" : 1e-5,
"relaxationFactor_info" : ["Только для оптимизатора RegularstepGradientDescent.",
"Величина, определяющая во сколько раз уменьшится шаг оптимизатора при смене направлении оптимизации",
"(это происходит при перескоке оптимизатора через минимум)."],
"relaxationFactor" : 0.7,
"gradientMagnitudeTolerance_info" : ["Только для оптимизатора RegularstepGradientDescent.",
"Если на очередном шаге величина градиента меньше заданной,",
"то на текущем уровне сжатия оптимизация останавливается."],
"gradientMagnitudeTolerance" : 1e-6,
"ConvergenceMinimumValue_info" : ["Только для оптимизатора GradientDescent.",
"Если величина градиента меньше заданной на протяжении заданного числа шагов,",
"то на текущем уровне сжатия оптимизация останавливается."],
"ConvergenceMinimumValue" : 1e-7,
"ConvergenceWindowSize_info" : ["Задает число шагов, на протяжении которых",
"градиент должен быть меньше заданного значения",
"для остановки оптимизации на текущем уровне сжатия изображения."],
"ConvergenceWindowSize" : 10,
"ShrinkFactors_info" : ["Задает уровни сжатия изображения,",
"на которых последовательно производится оптимизация.",
"Чаще всего производится сначала совмещение при большом сжатии в 4 раза,",
"потом при сжатии в 2 раза, потом в полном разрешении."],
"ShrinkFactors" : [4,2,1],
"SmoothingSigmas_info" : ["Задает гауссово размытие на указанный уровнях сжатия изображения",
"для большей гладкости оптимизируемой функции метрики."],
"SmoothingSigmas" : [2,1,0]