[Python VTK] Чтение результатов сегментации двухмерных последовательностей медицинских изображений и выполнение трехмерной реконструкции

1. Описание проблемы

Недавно столкнулся с такой проблемой при разработке:

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

Вот результаты сегментации:

Рисунок 1: Результаты сегментации изображений МРТ простаты Рисунок 1: Результаты сегментации изображений МРТ простатыРисунок 1: Результаты сегментации МРТ-изображений предстательной железы

Ниже приведена маска маски чтения:

Рисунок 2: Маска сегментации изображения Рисунок 2: Маска сегментации изображенияРисунок 2: Маска сегментации изображения
Как выполнить трехмерную реконструкцию этих двухмерных изображений является сложной задачей Автор использует vtk для операций моделирования.

Два, решение

0. написать впереди

Трехмерная реконструкция медицинских изображений сама по себе является горячей технологией, и эта технология не нова.Автор изучил несколько блогов и других материалов первого и разобрался со своим решением, стремясь общаться со всеми.Если у вас есть лучшее Схема моделирования, добро пожаловать на общение со мной в любое время!

1. Подготовка

Для 3D-реконструкции медицинских изображений в первую очередь необходимо обеспечить четко видимые контуры и маски. (Как показано на рисунке 2)

Используемые библиотеки:

  • vtk, вы можете установить его pip install vtkнапрямую

2. Файловая структура

  • папка маски (используется для хранения маски результата сегментации, имя изображения mask_0.png, mask_1.png, mask_2.pngи т. д. 20 изображений)
  • vtk_gaussian.py (скрипт Python для выполнения и 3D-реконструкции)

как показано на рисунке:

Рисунок 3: Структура файла, используемая проектом Рисунок 3: Структура файла, используемая проектомРисунок 3: Структура файла, используемая проектом

3. Объяснение кода

3.0 Полный код

Я знаю, что некоторые друзья спешат, поэтому вот полный код:

import vtk

# 定义渲染窗口、交互模式
aRender = vtk.vtkRenderer()
Renwin = vtk.vtkRenderWindow()
Renwin.AddRenderer(aRender)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(Renwin)

# 定义个图片读取接口
# 读取PNG图片就换成PNG_Reader = vtk.vtkPNGReader()
PNG_Reader = vtk.vtkPNGReader()
PNG_Reader.SetNumberOfScalarComponents(1)
PNG_Reader.SetFileDimensionality(2)  # 说明图像是三维的

# 定义图像大小,本行表示图像大小为(512*512*240)
PNG_Reader.SetDataExtent(0, 256, 0, 256, 0, 19)
# 设置图像的存放位置
name_prefix = ['mask/mask_']
PNG_Reader.SetFilePrefix(name_prefix[0])

# 设置图像前缀名字
# 表示图像前缀为数字(如:0.jpg)
PNG_Reader.SetFilePattern("%s%d.png")
PNG_Reader.Update()
PNG_Reader.SetDataByteOrderToLittleEndian()
spacing = [1.0, 1.0, 2.5]  # x, y 方向上的间距为 2 像素,z 方向上的间距为 2.5 像素
PNG_Reader.GetOutput().SetSpacing(spacing)

# 高斯平滑
gauss = vtk.vtkImageGaussianSmooth()
gauss.SetInputConnection(PNG_Reader.GetOutputPort())
gauss.SetStandardDeviations(1.0, 1.0, 1.0)
gauss.SetRadiusFactors(1.0, 1.0, 1.0)
gauss.Update()

# 计算轮廓的方法
contour = vtk.vtkMarchingCubes()
gauss.GetOutput().SetSpacing(spacing)
contour.SetInputConnection(gauss.GetOutputPort())
contour.ComputeNormalsOn()
contour.SetValue(0, 100)

mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(contour.GetOutputPort())
mapper.ScalarVisibilityOff()

actor = vtk.vtkActor()
actor.SetMapper(mapper)

renderer = vtk.vtkRenderer()
renderer.SetBackground([1.0, 1.0, 1.0])
renderer.AddActor(actor)

window = vtk.vtkRenderWindow()
window.SetSize(512, 512)
window.AddRenderer(renderer)

interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(window)

# 开始显示
if __name__ == '__main__':
    window.Render()
    interactor.Initialize()
    interactor.Start()

3.1 Определите окно рендеринга и интерактивный режим

import vtk

# 定义渲染窗口、交互模式
aRender = vtk.vtkRenderer()
Renwin = vtk.vtkRenderWindow()
Renwin.AddRenderer(aRender)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(Renwin)

Почти все мои сценарии 3D-реконструкции включают этот контент, и это также часть для инициализации интерактивного окна vtk.Для получения дополнительной информации вы можете обратиться к официальным документам vtk или другим техническим блогам.

3.2 Чтение последовательностей 2D-изображений — определение интерфейса чтения

Чтобы прочитать все mask_0.pngполученные mask_19.pngизображения, вам необходимо определить интерфейс чтения изображений (vtk.vtkXxxReader).

Авторское изображение является .pngформатным, поэтому используйте vtk.vtkPNGReader()для чтения изображение.

PNG_Reader = vtk.vtkPNGReader()
PNG_Reader.SetNumberOfScalarComponents(1)
PNG_Reader.SetFileDimensionality(2)  # 说明图像是二维的

Здесь вы можете выбрать разные vtkReader в соответствии с различными форматами изображений.Если это изображение в .jpgформате , вы можете внести следующие изменения:

JPG_Reader = vtk.vtkJPEGReader()
# your code here...

3.3 Чтение последовательности двумерных изображений — предварительные настройки и чтение изображения

# 定义图像大小,本人表示图像大小为(256*256)
# 后两个参数是图片的数目,本人这里所用的图像共20张,所以就输入0, 19
# 在后续读取的时候,会根据这个序列进行读取
PNG_Reader.SetDataExtent(0, 256, 0, 256, 0, 19)
# 设置图像的存放位置
name_prefix = ['mask/mask_']
PNG_Reader.SetFilePrefix(name_prefix[0])

# 表示图像前缀为数字(如:0.jpg)
PNG_Reader.SetFilePattern("%s%d.png")
PNG_Reader.Update()
PNG_Reader.SetDataByteOrderToLittleEndian()

Этот код представляет собой некоторые предварительные настройки для чтения изображений. SetDataExtent()Настройка параметров функции будет иметь определенное влияние на последующую обработку изображения, пожалуйста, правильно заполните размер и количество изображений, которые вы используете!

SetFilePrefix()Функция будет заблокирована в соответствии с переданной строкой. Здесь необходимо обратить особое внимание :

  • Мои изображения хранятся в maskпапках, и имя каждого изображения: mask_0.pngи mask_1.pngт. д.
  • При установке Префикса здесь необходимо ввестиmask/mask_
  • Следующая SetFilePattern()функция будет автоматически считывать номер, потому что префикс был установлен, и здесь нет необходимости выполнять какие-то обычные операторские операции.

3.4 Объем данных изображения небольшой, а результат 3D-моделирования очень плоский

Решение. Вы можете увеличить расстояние между изображениями, чтобы исправить это, следуя приведенному выше коду:

PNG_Reader.SetDataByteOrderToLittleEndian()
spacing = [1.0, 1.0, 2.5]  # x, y 方向上的间距为 2 像素,z 方向上的间距为 2.5 像素
PNG_Reader.GetOutput().SetSpacing(spacing)

Прочитав рисунок, вы можете установить spacingсписок , которые представляют x, y, zинтервалы трех измерений, а я zувеличиваю интервалы измерений до 2.5, такая операция будет иметь значительный эффект при последующем моделировании. Конкретное содержание выглядит следующим образом:

Рисунок 4: Результаты моделирования двух разных интервалов, левое изображение z = 1,0, правое изображение z = 2,5 Рисунок 4: Результаты моделирования двух разных интервалов, левое изображение z = 1,0, правое изображение z =2,5Рис. 4: Результаты моделирования двух разных интервалов, левое изображение — z."="1.0 , на картинке справа z"="2,5

Для того, чтобы результат моделирования приблизился к форме органа, я рекомендую задать интервал между 2D-изображениями .

3.5 Сглаживание результатов 3D-реконструкции — сглаживание по Гауссу

Результат оригинальной лепки "явно слоистый" и не особо красивый. Автор использует схему сглаживания Гаусса для сглаживания изображения.

Если у вас есть лучшее решение для сглаживания, добро пожаловать на общение со мной!

# 高斯平滑
gauss = vtk.vtkImageGaussianSmooth()
gauss.SetInputConnection(PNG_Reader.GetOutputPort())
gauss.SetStandardDeviations(1.0, 1.0, 1.0)
gauss.SetRadiusFactors(1.0, 1.0, 1.0)
gauss.Update()

Рисунок 5: Результаты сглаживания двух разных интервалов, левое изображение не сглажено, правое изображение использует сглаживание по ГауссуРисунок 5: Результаты сглаживания двух разных интервалов, левое изображение не сглажено, а правое изображение представляет собой сглаживание по Гауссу.

3.6 Вычисление контура и выделение краев

После сглаживания по Гауссу выполняется выделение ребер.

# 计算轮廓的方法
contour = vtk.vtkMarchingCubes()
gauss.GetOutput().SetSpacing(spacing)
contour.SetInputConnection(gauss.GetOutputPort())
contour.ComputeNormalsOn()
contour.SetValue(0, 100)

3.7 Работа конвейера и визуальное отображение

Следующий код является частью отображения vtk. Автор обычно не трогает его, а также является неотъемлемым содержанием каждого скрипта. Если вам интересна эта часть, вам следует обратиться к официальному документу vtk.

mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(contour.GetOutputPort())
mapper.ScalarVisibilityOff()

actor = vtk.vtkActor()
actor.SetMapper(mapper)

renderer = vtk.vtkRenderer()
renderer.SetBackground([1.0, 1.0, 1.0])
renderer.AddActor(actor)

window = vtk.vtkRenderWindow()
window.SetSize(512, 512)
window.AddRenderer(renderer)

interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(window)

# 开始显示
if __name__ == '__main__':
    window.Render()
    interactor.Initialize()
    interactor.Start()

3. Некоторый опыт обмена библиотекой vtk

1. питон втк

Лично я чувствую, что разработка python vtk не имеет стиля pythonic.Разработчики привнесли некоторые идеи разработки cpp в библиотеку/дизайн интерфейса python, что заставляет меня писать, как жевать воск.Это также видно из приведенного выше кода. что у него сильный cpp-стиль.

Но пока код может работать, я должен сказать, что vtk по-прежнему является очень мощным инструментом 3D-реконструкции!

2. Два способа ввода данных

2.1 .GetOutputPort()и.SetInputConnection()

Вы увидите такие предложения contour.SetInputConnection(gauss.GetOutputPort()), как .

Эти две функции обычно появляются парами и передаются вверх и вниз.

2.1 .GetOutput()и.SetInputData()

Когда я обращаюсь к блогам других блоггеров, я также вижу такие записи, например:

contour.SetInputData(gauss.GetOutput())

Эти две функции обычно появляются парами, и результаты обработки передаются вверх и вниз.

3. vtkImageData и vtkPolyData

В процессе разработки вы можете столкнуться с множеством ошибок, среди которых обязательно будут ошибки типа данных vtk. Я собрал форму:

Имя Тип ввода Тип возврата Переменная
vtk.vtkPNGReader() ? vtkImageData PNG_Reader
vtk.vtkImageGaussianSmooth() vtkImageData vtkImageData Гаусс
vtk.vtkМаршевые кубы() vtkImageData vtkPolyData контур
vtk.vtkPolyDataNormals() vtkImageData vtkPolyData норм фильтр

Надеюсь помочь вам решить некоторые сомнения в процессе разработки.

постскриптум

Есть несколько блогов о 3D-реконструкции медицинских изображений.Автор надеется дать искру и вместе добиться прогресса!

Код реконструкции, использованный автором, упакован на облачный диск Baidu, скачать его можно по ссылке ниже:

ссылка для скачивания

Код извлечения: jpt3

Guess you like

Origin blog.csdn.net/Samurai_Bushido/article/details/129915969