import vtk
import os
import numpy as np
import tkinter as tk
from toor.Phantoms import NEMAIQ2008NU
[docs]
class SliceViewer:
def __init__(self, master, data3D=None, scale_z=0.5, scale_x=0.5, scale_y=0.5, colormap='hot.cl' ):
self.data3D = data3D
self.colormap = colormap
direct = os.path.dirname(os.path.dirname(__file__))
self.path_colormap = os.path.join(direct, "ControlUI", "colormap_files")
self.phantom = NEMAIQ2008NU(centerPhantom=[0, 0, scale_z*data3D.shape[2] / 2])
self.rods = [ self.phantom._rod1mm, self.phantom._rod2mm, self.phantom._rod3mm, self.phantom._rod4mm, self.phantom._rod5mm]
self.cold_rods = [self.phantom._waterChamberFilling, self.phantom._airChamberFilling]
self.scale_x = scale_x
self.scale_y = scale_y
self.scale_z = scale_z
self.master = master
self.master.title("VTK with Tkinter Scale")
self.frame = tk.Frame(master)
self.frame.pack(fill=tk.BOTH, expand=1)
self.vtk_widget = tk.Canvas(self.frame, width=800, height=600)
self.vtk_widget.pack(fill=tk.BOTH, expand=1)
self.renderer = vtk.vtkRenderer()
self.render_window = vtk.vtkRenderWindow()
self.render_window.AddRenderer(self.renderer)
self.interactorStyleImage = vtk.vtkInteractorStyleImage()
self.interactorStyleImage.SetInteractionModeToImageSlicing()
self.interactorStyle3D = vtk.vtkInteractorStyleTrackballCamera()
self.interactor = vtk.vtkRenderWindowInteractor()
self.interactor.SetInteractorStyle(self.interactorStyleImage)
self.interactor.SetRenderWindow(self.render_window)
self.renderer_entered = None
self._listOfRenderers = []
self._resliced_main_window = []
self._min_color = 40
self._max_color = 1300
self._ambient = 1.1
self._specular = 0.4
self._volumeRotationX = 0
self._volumeRotationY = 0
self._volumeRotationZ = 0
self._zoomVolume = 1
self._maxValueForVolume = data3D.max()
self._minValueForVolume = data3D.min()
[docs]
def maxValueForVolume(self):
return self._maxValueForVolume
[docs]
def minValueForVolume(self):
return self._minValueForVolume
[docs]
def setMaxValueForVolume(self, max_value):
self._maxValueForVolume = max_value
[docs]
def setZoomVolume(self, zoom):
self._zoomVolume = zoom
[docs]
def setVolumeRotation(self, alpha, beta, gamma):
self._volumeRotationX = alpha
self._volumeRotationY = beta
self._volumeRotationZ = gamma
[docs]
def setColorMapLimits(self, v_lim):
self._min_color = v_lim[0]
self._max_color = v_lim[1]
[docs]
def setAmbient(self, ambient):
self._ambient = ambient
[docs]
def setSpecular(self, specular):
self._specular = specular
[docs]
def addObservers(self):
self.interactorStyleImage.AddObserver("MouseMoveEvent",
lambda obj, event: self.MouseMoveCallback(obj, event))
self.interactorStyleImage.AddObserver("MouseWheelForwardEvent",
lambda obj, event: self.wheelForwardCallback(obj, event))
self.interactorStyleImage.AddObserver("MouseWheelBackwardEvent",
lambda obj, event: self.wheelForwardCallback(obj, event))
[docs]
def addVolumeRendering(self):
dims = self.data3D.shape
dataImporter = vtk.vtkImageImport()
data_string = self.data3D.tobytes()
dataImporter.CopyImportVoidPointer(data_string, len(data_string))
dataImporter.SetDataScalarTypeToFloat()
dataImporter.SetNumberOfScalarComponents(1)
dataImporter.SetDataExtent(0, dims[0] - 1, 0, dims[1] - 1, 0, dims[2] - 1)
# dataImporter.SetDataExtent(-dims[0]*self.scale_x/2, dims[0]*self.scale_x/2, -dims[1]*self.scale_y/2, dims[1]*self.scale_y/2, -dims[2]*self.scale_z/2, dims[2]*self.scale_z/2)
dataImporter.SetWholeExtent(0, dims[0] - 1, 0, dims[1] - 1, 0, dims[2] - 1)
# dataImporter.SetWholeExtent(-dims[0]*self.scale_x/2, dims[0]*self.scale_x/2, -dims[1]*self.scale_y/2, dims[1]*self.scale_y/2, -dims[2]*self.scale_z/2, dims[2]*self.scale_z/2)
dataImporter.Update()
reader = dataImporter
self.image_data = dataImporter.GetOutput()
# Volume rendering setup
volume_mapper = vtk.vtkSmartVolumeMapper()
volume_mapper.SetInputConnection(reader.GetOutputPort())
# volume_mapper.SetInterpolationModeToCubic()
volume_property = vtk.vtkVolumeProperty()
volume_property.ShadeOn()
# volume_property.SetInterpolationTypeToLinear()
# volume_property.SetInterpolationTypeToCubic()
# composite_opacity = vtk.vtkPiecewiseFunction()
# composite_opacity.AddPoint(0, 0.0)
# composite_opacity.AddPoint(self.data3D.max(), 1.0)
# volume_property.SetScalarOpacity(composite_opacity)
color = vtk.vtkColorTransferFunction()
color.SetColorSpaceToRGB()
file_name = os.path.join(self.path_colormap, self.colormap)
color_map_file = np.loadtxt(file_name)
normalize_colormap = self._maxValueForVolume
start_color = self._min_color # 40
end_color = self._max_color # 1300
increment_color = 0
for row in range(0, len(color_map_file)):
if row < start_color:
color.AddRGBPoint(float(color_map_file[row][0]) * normalize_colormap,
float(color_map_file[0][1]), float(color_map_file[0][2]), float(color_map_file[0][3]))
elif row > end_color:
color.AddRGBPoint(float(color_map_file[row][0]) * normalize_colormap,
float(color_map_file[-1][1]), float(color_map_file[-1][2]),
float(color_map_file[-1][3]))
else:
increment_color += len(color_map_file) / abs(start_color - end_color)
if int(np.round(increment_color, 0)) < len(color_map_file):
color.AddRGBPoint(float(color_map_file[row][0]) * normalize_colormap,
float(color_map_file[int(np.round(increment_color, 0))][1]),
float(color_map_file[int(np.round(increment_color, 0))][2]),
float(color_map_file[int(np.round(increment_color, 0))][3]))
color.AddRGBPoint(0, float(color_map_file[0][1]), float(color_map_file[0][2]), float(color_map_file[0][3]))
color.AddRGBPoint(self._maxValueForVolume, float(color_map_file[-1][1]), float(color_map_file[-1][2]),
float(color_map_file[-1][3]))
alphaChannelFunc = vtk.vtkPiecewiseFunction()
alphaChannelFunc.AddPoint(0, 0.0)
alphaChannelFunc.AddPoint(self._maxValueForVolume * 0.07, 0.0)
# alphaChannelFunc.AddPoint(self._maxValueForVolume * 0.2, 0.005) # 0.03 #mice 0.005
# 0.03 #mice 0.005
alphaChannelFunc.AddPoint(self._maxValueForVolume, 1)
# alphaChannelFunc.AddPoint(self._maxValueForVolume, 0.5)
volume_property.SetColor(color)
volume_property.SetInterpolationType(2)
volume_property.SetAmbient(self._ambient)
volume_property.SetSpecular(self._specular)
volume_property.SetScalarOpacity(alphaChannelFunc)
volume = vtk.vtkVolume()
volume.SetMapper(volume_mapper)
volume.SetProperty(volume_property)
# set scale
volume.SetScale(self.scale_x, self.scale_y, self.scale_z)
volume_renderer = vtk.vtkRenderer()
volume_renderer.AddVolume(volume)
volume_renderer.SetBackground(1, 1, 1)
volume_renderer.SetBackground(0, 0, 0)
# volume_renderer.SetBackground(color_map_file[0][1], color_map_file[0][2], color_map_file[0][3])
volume.RotateX(self._volumeRotationX) # 90
volume.RotateY(self._volumeRotationY) # 75
volume.RotateZ(self._volumeRotationZ) # 60
volume_renderer.ResetCamera()
volume_renderer.GetActiveCamera().Zoom(self._zoomVolume)
return reader, volume_renderer, color_map_file, color
[docs]
def derenzo(self, outputFilename=None, recalculate_max_value=True):
# Read the volume data
self.data3D = self.prepare_data(voxeldata=self.data3D)
if recalculate_max_value:
self._maxValueForVolume = self.data3D.max()
self._minValueForVolume = self.data3D.min()
# Convert self.data3D to VTK format
reader, volume_renderer, color_map_file, color = self.addVolumeRendering()
self.interactor.SetInteractorStyle(self.interactorStyle3D)
self.render_window.AddRenderer(volume_renderer)
# Add title
self.renderer = volume_renderer
self.renderWindow((600,600))
self.saveImageInPDF(outputFilename=outputFilename)
self.interactor.Start()
[docs]
def renderWindow(self, size=(1875, 1875)): #1875
self.render_window.SetSize(size)
# self.save_screenshot()
self.interactor.Initialize()
self.render_window.Render()
[docs]
def saveImageInPDF(self, outputFilename=None):
pdfExporter = vtk.vtkGL2PSExporter()
pdfExporter.SetRenderWindow(self.render_window)
if outputFilename is None:
outputFilename = "../../outputs/teste"
pdfExporter.SetFileFormatToPDF() # save as pdf
pdfExporter.SetFilePrefix(outputFilename)
pdfExporter.Write()
# save as png
window_to_image_filter = vtk.vtkWindowToImageFilter()
window_to_image_filter.SetInput(self.render_window)
window_to_image_filter.SetScale(1) # Image quality
window_to_image_filter.SetInputBufferTypeToRGBA()
window_to_image_filter.Update()
writer = vtk.vtkPNGWriter()
writer.SetFileName(outputFilename + ".png")
writer.SetInputConnection(window_to_image_filter.GetOutputPort())
# 300 dpi
writer.Write()
[docs]
def MiceNaf(self, filename=None, recalculate_max_value=True, only_scalar_bar=False, render_volume=True, window_size=(600, 600)):
self.data3D = self.prepare_data(voxeldata=self.data3D)
if recalculate_max_value:
self._maxValueForVolume = self.data3D.max()
self._minValueForVolume = self.data3D.min()
# Convert self.data3D to VTK format
reader, volume_renderer, color_map_file, color = self.addVolumeRendering()
if only_scalar_bar:
filename = filename + "_scalar_bar"
overlay_renderer = vtk.vtkRenderer()
overlay_renderer.SetViewport(0.0, 0.0, 1.0, 1.0)
overlay_renderer.SetLayer(1)
self.render_window.SetNumberOfLayers(2)
self.render_window.AddRenderer(overlay_renderer)
#add colorbar
scaleActor = vtk.vtkScalarBarActor()
scaleActor.SetLookupTable(color)
scaleActor.SetOrientationToVertical()
scaleActor.SetNumberOfLabels(4)
scaleActor.SetLabelFormat("%2.1f")
scaleActor.SetPosition(0.1, 0.1)
scaleActor.SetWidth(0.5)
scaleActor.SetHeight(0.8)
# lavls in black
scaleActor.GetLabelTextProperty().SetColor(0, 0, 0)
# scaleActor.SetTitle("Activity (MBq/ml)")
# Create a text actor for the title
title_actor = vtk.vtkTextActor()
title_actor.SetInput("SUV")
# Customize title text properties
title_text_property = title_actor.GetTextProperty()
title_text_property.SetFontSize(24)
title_text_property.SetJustificationToCentered()
title_text_property.SetVerticalJustificationToCentered()
title_text_property.SetOrientation(90) # Rotate text 90 degrees
title_text_property.SetColor(0, 0, 0) # White color text for better visibility
# Position the title actor to the right of the scalar bar
title_actor.SetPosition(92, 300)
overlay_renderer.AddActor(scaleActor)
overlay_renderer.AddActor((title_actor))
# self.renderWindow(size=(73, 600))
self.renderWindow(size=(73, 600))
if render_volume:
self.render_window.AddRenderer(volume_renderer)
self.interactor.SetInteractorStyle(self.interactorStyle3D)
# Add title
self.renderer.SetUseDepthPeeling(1)
self.renderWindow(size=window_size)
self.saveImageInPDF(outputFilename=filename)
#
# self.createMovie(filename=filename + ".ogv")
self.interactor.Start()
[docs]
def NemaIQ2008(self, file_to_save=None, only_scalar_bar=True, recalculate_max_value=True):
# Read the volume data
self.data3D = self.prepare_data(voxeldata=self.data3D)
if recalculate_max_value:
self._maxValueForVolume = self.data3D.max()
self._minValueForVolume = self.data3D.min()
# Convert self.data3D to VTK format
reader, volume_renderer, color_map_file, color = self.addVolumeRendering()
self.renderer.SetUseDepthPeeling(1)
slice_x_renderer, slice_y_renderer, slice_z_renderer, volume_renderer, mip_reslice_x, mip_reslice_y, mip_reslice_z = self.addViewportsNema(reader, volume_renderer, color_map_file, color)
self._listOfRenderers = [volume_renderer, slice_x_renderer, slice_y_renderer, slice_z_renderer]
self._resliced_main_window = [mip_reslice_x, mip_reslice_y, mip_reslice_z, None]
# add observers
# self.interactor.AddObserver("MouseMoveEvent", self.MouseMoveCallback)
self.addObservers()
# Create an overlay renderer for the scalar bar
if only_scalar_bar:
overlay_renderer = vtk.vtkRenderer()
overlay_renderer.SetViewport(0.0, 0.0, 1.0, 1.0)
overlay_renderer.SetLayer(1)
self.render_window.SetNumberOfLayers(2)
self.render_window.AddRenderer(overlay_renderer)
#add colorbar
scaleActor = vtk.vtkScalarBarActor()
scaleActor.SetLookupTable(color)
scaleActor.SetOrientationToVertical()
scaleActor.SetNumberOfLabels(4)
scaleActor.SetLabelFormat("%2.1f")
scaleActor.SetPosition(0.1, 0.1)
scaleActor.SetWidth(0.5)
scaleActor.SetHeight(0.8)
# lavls in black
scaleActor.GetLabelTextProperty().SetColor(0, 0, 0)
# scaleActor.SetTitle("Activity (MBq/ml)")
# Create a text actor for the title
title_actor = vtk.vtkTextActor()
title_actor.SetInput("Activity (MBq/ml)")
# Customize title text properties
title_text_property = title_actor.GetTextProperty()
title_text_property.SetFontSize(24)
title_text_property.SetJustificationToCentered()
title_text_property.SetVerticalJustificationToCentered()
title_text_property.SetOrientation(90) # Rotate text 90 degrees
title_text_property.SetColor(0, 0, 0) # White color text for better visibility
# Position the title actor to the right of the scalar bar
title_actor.SetPosition(92, 300)
overlay_renderer.AddActor(scaleActor)
overlay_renderer.AddActor((title_actor))
self.renderWindow(size=(73, 600))
else:
# Add title
self.render_window.AddRenderer(volume_renderer)
self.render_window.AddRenderer(slice_x_renderer)
self.render_window.AddRenderer(slice_y_renderer)
self.render_window.AddRenderer(slice_z_renderer)
self.renderWindow()
self.saveImageInPDF(outputFilename=file_to_save)
#
self.interactor.Start()
[docs]
def addViewportsNema(self, reader, volume_renderer, color_map_file, color):
slice_x_renderer = vtk.vtkRenderer()
slice_y_renderer = vtk.vtkRenderer()
slice_z_renderer = vtk.vtkRenderer()
self.create_viewport(slice_z_renderer, [0.0, 0.0, 0.5, 0.5])
self.create_viewport(slice_x_renderer, [0.0, 0.5, 0.5, 1.0])
self.create_viewport(slice_y_renderer, [0.5, 0.5, 1.0, 1.0])
self.create_viewport(volume_renderer, [0.5, 0.0, 1.0, 0.5])
center = self.rods[0].center
print(center)
center[2] -= 5+1
center[0] /= self.scale_x
center[1] /= self.scale_y
center[2] /= self.scale_z
mip_reslice_x = self.create_reslice(reader.GetOutputPort(), slab_thickness=7, slab_mode="Max", center=center)
color_mapper_x = vtk.vtkImageMapToColors()
color_mapper_x.SetLookupTable(color)
color_mapper_x.SetInputConnection(mip_reslice_x.GetOutputPort())
color_mapper_x.Update()
slice_x_mapper = vtk.vtkImageResliceMapper()
slice_x_mapper.SetInputConnection(color_mapper_x.GetOutputPort())
slice_x_mapper.SliceFacesCameraOn()
slice_x_mapper.BorderOff()
# set interpolation type
slice_x_actor = vtk.vtkImageSlice()
slice_x_actor.SetMapper(slice_x_mapper)
# slice_x_actor.RotateY(90)
slice_x_renderer.AddViewProp(slice_x_actor)
slice_x_renderer.SetBackground(0, 0, 0)
#first color of the colormap is background
slice_x_renderer.SetBackground(color_map_file[0][1], color_map_file[0][2], color_map_file[0][3])
slice_x_renderer.ResetCamera()
slice_x_renderer.GetActiveCamera().Zoom(1)
slice_x_renderer.GetActiveCamera().Roll(90)
center = self.cold_rods[0].center
print(center)
center[2] -= 5+2
center[0] /= self.scale_x
center[1] /= self.scale_y
center[2] /= self.scale_z
mip_reslice_y = self.create_reslice(reader.GetOutputPort(), slab_thickness=20, slab_mode="Min", center=center)
color_mapper_y = vtk.vtkImageMapToColors()
color_mapper_y.SetLookupTable(color)
color_mapper_y.SetInputConnection(mip_reslice_y.GetOutputPort())
color_mapper_y.Update()
slice_y_mapper = vtk.vtkImageResliceMapper()
slice_y_mapper.SetInputConnection(color_mapper_y.GetOutputPort())
slice_y_mapper.SliceFacesCameraOn()
slice_y_mapper.SliceAtFocalPointOn()
slice_y_mapper.BorderOff()
slice_y_actor = vtk.vtkImageSlice()
slice_y_actor.SetMapper(slice_y_mapper)
slice_y_renderer.AddViewProp(slice_y_actor)
slice_y_renderer.SetBackground(0, 0, 0)
slice_y_renderer.SetBackground(color_map_file[0][1], color_map_file[0][2], color_map_file[0][3])
slice_y_renderer.ResetCamera()
slice_y_renderer.GetActiveCamera().Zoom(1)
slice_y_renderer.GetActiveCamera().Roll(90)
# middle slice center of the phantom
center = [self.scale_x*self.data3D.shape[0]/2, self.scale_y*self.data3D.shape[1]/2, self.scale_z*self.data3D.shape[2]/2]
print(center)
center = self.cold_rods[1].center
center[2] -= 5
center[0] = center[0]*self.scale_x +self.scale_x*self.data3D.shape[0] -3
print(center)
mip_reslice_z = self.create_reslice(reader.GetOutputPort(), slab_thickness=7, slab_mode="Max", rotation_type="Sagittal", center=center)
color_mapper_z = vtk.vtkImageMapToColors()
color_mapper_z.SetLookupTable(color)
color_mapper_z.SetInputConnection(mip_reslice_z.GetOutputPort())
color_mapper_z.Update()
slice_z_mapper = vtk.vtkImageResliceMapper()
slice_z_mapper.SetInputConnection(color_mapper_z.GetOutputPort())
slice_z_mapper.SliceFacesCameraOn()
slice_z_mapper.SliceAtFocalPointOn()
slice_z_mapper.BorderOff()
slice_z_actor = vtk.vtkImageSlice()
slice_z_actor.SetMapper(slice_z_mapper)
slice_z_renderer.AddViewProp(slice_z_actor)
slice_z_renderer.SetBackground(0, 0, 0)
slice_z_renderer.SetBackground(color_map_file[0][1], color_map_file[0][2], color_map_file[0][3])
slice_z_renderer.ResetCamera()
slice_z_renderer.GetActiveCamera().Zoom(1.5)
slice_z_renderer.GetActiveCamera().Roll(180)
return slice_x_renderer, slice_y_renderer, slice_z_renderer, volume_renderer, mip_reslice_x, mip_reslice_y, mip_reslice_z
# slice_z_renderer.GetActiveCamera().Yaw(90)
# textActor = vtk.vtkTextActor()
# textActor.SetTextScaleModeToNone()
# textActor.GetTextProperty().SetFontSize(24)
# textActor.GetTextProperty().SetColor(1, 1, 1)
# textActor.SetInput("NEMA IQ 2008 Phantom")
# textActor.SetPosition(10, 10)
# self.renderer.AddActor(textActor)
# # Add scale
# scaleActor = vtk.vtkScalarBarActor()
# scaleActor.SetLookupTable(color)
# scaleActor.SetTitle("Activity (Bq/ml)")
# scaleActor.SetNumberOfLabels(5)
# scaleActor.SetLabelFormat("%6.1f")
# scaleActor.SetPosition(0.1, 0.1)
# scaleActor.SetWidth(0.8)
# scaleActor.SetHeight(0.1)
# scaleActor.SetOrientationToHorizontal()
# scaleActor.GetTitleTextProperty().SetColor(1, 1, 1)
# scaleActor.GetLabelTextProperty().SetColor(1, 1, 1)
# self.renderer.AddActor(scaleActor)
# Add save button
# self.save_button = tk.Button(master, text="Save Screenshot", command=self.save_screenshot)
# self.save_button.pack()
# # Save render window as png
# writer = vtk.vtkPNGWriter()
# writer.SetFileName("../../outputs/NeMa_renderODRTVF.png")
# writer.SetInputConnection(windowToImageFilter.GetOutputPort())
# writer.Write()
[docs]
def createMovie(self, filename):
# perform a 360 degree rotation of the volume
# create a camera
self.renderer.SetUseDepthPeeling(1)
# self.ren_volume.SetBackground(0, 0, 0) # black
# self.ren_volume.ResetCamera()
# self.renderWin = renderWin
self.interactor.Initialize()
# self.call_backs = [None] * len(self.detectors)
# for i in range(len(self.detectors)):
# for i in range(5):
camera = self.renderer.GetActiveCamera()
camera.Azimuth(90)
camera.Roll(-90)
# camera.Pitch(3)
# camera.Elevation(5)
# camera.Yaw(5)
camera.SetViewAngle(15)
# camera.SetFocalDistance()
# camera.SetClippingRange(0,400)
windowToImageFilter = vtk.vtkWindowToImageFilter()
windowToImageFilter.SetInput(self.render_window)
# windowToImageFilter.SetInputBufferTypeToRGBA()
# windowToImageFilter.ReadFrontBufferOff()
windowToImageFilter.Update()
# writer = vtk.vtkAVIWriter()
# writer.SetInputConnection(windowToImageFilter.GetOutputPort())
# writer.SetFileName("test.avi")
# writer.Start()
#
moviewriter = vtk.vtkOggTheoraWriter()
moviewriter.SetInputConnection(windowToImageFilter.GetOutputPort())
moviewriter.SetFileName(filename)
moviewriter.Start()
ca = vtkTimerCallback(moviewriter, windowToImageFilter)
ca.camera = camera
self.interactor.AddObserver('TimerEvent', ca.execute)
timerId = self.interactor.CreateRepeatingTimer(100)
# Because nothing will be rendered without any input, we order the first render manually before control is handed over to the main-loop.
self.renderer.Render()
self.interactor.Start()
self.moviewriter = moviewriter
self.moviewriter.End()
[docs]
def save_screenshot(self):
window_to_image_filter = vtk.vtkWindowToImageFilter()
window_to_image_filter.SetInput(self.render_window)
window_to_image_filter.SetScale(1) # Image quality
window_to_image_filter.SetInputBufferTypeToRGBA()
window_to_image_filter.Update()
writer = vtk.vtkPNGWriter()
writer.SetFileName("screenshot.png")
writer.SetInputConnection(window_to_image_filter.GetOutputPort())
writer.Write()
[docs]
def prepare_data(self, voxeldata=None, colormap=None, path=None, z_pos=None, data3D=None):
# voxeldata = np.random.rand(100, 100, 100) # Example data
z_pos = voxeldata.shape[2]
data3D = voxeldata
# data3D = ndimage.median_filter(data3D, size=3)
# data3D = ndimage.gaussian_filter(data3D, sigma=0.57)
# data3D =ndimage.filters.convolve(data3D, np.ones((3, 1, 1)) / 9)
# wavelet filter on the image
# Reconstruct the denoised image
# Adjust the parameters according to your requirements
patch_size = 1 # Size of patches used for denoising
patch_distance = 1 # Maximum distance for patches to be considered similar
h = 0.0005 # Smoothing parameter (higher values give stronger smoothing)
# Apply non-local means denoising
# data3D = denoise_nl_means(data3D, patch_size=patch_size, patch_distance=patch_distance, h=h)
# denoised_image = pywt.idwtn(coeffs_thresh, 'haar')
xx = (np.tile(np.arange(0, data3D.shape[0]), (data3D.shape[0], 1)) - (data3D.shape[0] - 1) / 2) ** 2
yy = (np.tile(np.arange(0, data3D.shape[1]), (data3D.shape[1], 1)) - (data3D.shape[1] - 1) / 2) ** 2
xx = xx.T
try:
circle_cut = xx + yy - (data3D.shape[1] * 0.5) ** 2
circle_cut[circle_cut > 0] = 0
circle_cut[circle_cut < 0] = 1
circle_cut = np.tile(circle_cut[:, :, None], (1, 1, data3D.shape[2]))
data3D = data3D * circle_cut
except ValueError:
pass
data3D[:, :, :14] = 0 # 5
data3D[:, :, -25 :] = 0 #-5
# data3D[:, :7, :] = 0 # 5
# data3D[:, -7:, :] = 0 # -5
# transforme array for the axis 1 has the same shape as the axis 0
add_missing = data3D.shape[0] - data3D.shape[1]
print("add missing", add_missing)
if add_missing > 0:
data3D = np.pad(data3D, ((0, 0), (0, add_missing), (0, 0)), 'constant')
elif add_missing < 0:
data3D = np.pad(data3D, ((0, -add_missing), (0, 0), (0, 0)), 'constant')
size = data3D.shape
w, h, d = size
stack = np.zeros((w, d, h))
for j in range(0, z_pos):
stack[:, j, :] = data3D[:, :, j]
stack = np.require(stack, dtype=np.float32)
# data is with the wrong order per slice
# stack = np.swapaxes(stack, 0, 2)
#add 200 zeros in axis 0
#the
# stack = np.swapaxes(stack, 1, 2)
return stack
[docs]
def create_viewport(self, renderer, viewport):
renderer.SetViewport(viewport[0], viewport[1], viewport[2], viewport[3])
[docs]
def create_reslice(self, input_port, slab_thickness, slab_mode, rotation_type="Coronal", center=[0, 0, 0],
azimuthal_angle=0, polar_angle=0):
newResliceAxes = vtk.vtkMatrix4x4()
if rotation_type == "Axial":
newResliceAxes.DeepCopy((1, 0, 0, center[0],
0, 1, 0, center[2],
0, 0, 1, center[1],
0, 0, 0, 1))
elif rotation_type == "Coronal":
newResliceAxes.DeepCopy((1, 0, 0, center[0],
0, 0, 1, center[2],
0, -1, 0, center[1],
0, 0, 0, 1))
elif rotation_type == "Sagittal":
newResliceAxes.DeepCopy((0, 0, 1, center[0],
0, 1, 0, center[2],
-1, 0, 0, center[1],
0, 0, 0, 1))
reslice = vtk.vtkImageSlabReslice()
reslice.SetInputConnection(input_port)
reslice.SetResliceAxes(newResliceAxes)
reslice.SetSlabThickness(slab_thickness)
reslice.SetInterpolationModeToCubic()
if slab_mode == "Mean":
reslice.SetBlendModeToMean()
elif slab_mode == "Max":
reslice.SetBlendModeToMax()
elif slab_mode == "Min":
reslice.SetBlendModeToMin()
reslice.Update()
return reslice
[docs]
def MouseMoveCallback(self, obj, event):
(lastX, lastY) = self.interactor.GetLastEventPosition()
(mouseX, mouseY) = self.interactor.GetEventPosition()
renderer_entered = self.interactor.FindPokedRenderer(mouseX, mouseY)
# print('Mouse moving')
# print(renderer_entered)
if self._listOfRenderers[0] == renderer_entered:
# print('3D')
# pass
self.interactor.SetInteractorStyle(
self.interactorStyle3D)
self.interactorStyle3D.OnMouseMove()
else:
# print('Slicers')
# self.interactorStyleImage = vtk.vtkInteractorStyleImage()
# self.interactorStyleImage.SetInteractionModeToImageSlicing()
# self.interactorMainWindow.SetInteractorStyle(self.interactorStyleImage)
# index_renderer = self.parent.populateMainWindowVTK.listOfRenderers.index(
# renderer_entered) - 1 # testing -- put as dict
# if self.actions["Slicing"] == 1:
# deltaY = mouseY - lastY
# # self.resliced_main_window[index_renderer].Update()
# sliceSpacing = \
# self.parent.populateMainWindowVTK.resliced_main_window[index_renderer].GetOutput().GetSpacing()[2]
# matrix = self.parent.populateMainWindowVTK.resliced_main_window[index_renderer].GetResliceAxes()
# center = matrix.MultiplyPoint((0, 0, sliceSpacing * deltaY, 1))
# matrix.SetElement(0, 3, center[0])
# matrix.SetElement(1, 3, center[1])
# matrix.SetElement(2, 3, center[2])
# self.parent.populateMainWindowVTK.vtkWidget.GetRenderWindow().Render()
#
# else:
self.interactorStyleImage.SetInteractionModeToImageSlicing()
self.interactor.SetInteractorStyle(
self.interactorStyleImage)
self.interactorStyleImage.OnMouseMove()
self.renderer_entered = renderer_entered
# override scroll event and update reslice
[docs]
def wheelForwardCallback(self, obj, event):
if event == "MouseWheelForwardEvent":
increment = 2
elif event == "MouseWheelBackwardEvent":
increment = -2
index_renderer = self._listOfRenderers.index(self.renderer_entered)-1
# if self.parent.populateMainWindowVTK.resliced_main_window[index_renderer] is None:
# return
sliceSpacing = self._resliced_main_window[index_renderer].GetOutput().GetSpacing()[2]
matrix = self._resliced_main_window[index_renderer].GetResliceAxes()
center = matrix.MultiplyPoint((0, 0, sliceSpacing * increment, 1))
matrix.SetElement(0, 3, center[0])
matrix.SetElement(1, 3, center[1])
matrix.SetElement(2, 3, center[2])
# set the reslice axes
self._resliced_main_window[index_renderer].SetResliceAxes(matrix)
self.render_window.Render()
[docs]
class vtkTimerCallback():
def __init__(self, writer=None, imageFilter=None):
self.timer_count = 0
self.writer = writer
self.imageFilter = imageFilter
[docs]
def execute(self,obj,event):
print(self.timer_count)
# self.actor.SetPosition(self.timer_count, self.timer_count,0)
if self.timer_count <360:
focal_position =np.array([1000,1000,500])
alpha = np.deg2rad(self.timer_count)
beta = 0
gamma = 0
rotation_matrix = np.array([[np.cos(alpha) * np.cos(beta),
np.cos(alpha) * np.sin(beta) * np.sin(gamma) - np.sin(alpha) * np.cos(gamma),
np.cos(alpha) * np.sin(beta) * np.cos(gamma) + np.sin(alpha) * np.sin(gamma)],
[np.sin(alpha) * np.cos(beta),
np.sin(alpha) * np.sin(beta) * np.sin(gamma) + np.cos(alpha) * np.cos(gamma),
np.sin(alpha) * np.sin(beta) * np.sin(gamma) - np.cos(alpha) * np.sin(gamma)],
[-np.sin(beta),
np.cos(beta) * np.sin(gamma),
np.cos(beta) * np.cos(gamma)]], dtype=np.float32)
focal_position = (np.dot(focal_position, rotation_matrix))
self.camera.SetPosition(focal_position)
# elif self.timer_count <370:
# self.camera.Zoom((self.timer_count-360)*.1+1)
#
# else:
# focal_position = np.array([1000, 1000, 0])
# alpha = np.deg2rad(self.timer_count)
# beta = 0
# gamma = 0
# rotation_matrix = np.array([[np.cos(alpha) * np.cos(beta),
# np.cos(alpha) * np.sin(beta) * np.sin(gamma) - np.sin(alpha) * np.cos(gamma),
# np.cos(alpha) * np.sin(beta) * np.cos(gamma) + np.sin(alpha) * np.sin(gamma)],
# [np.sin(alpha) * np.cos(beta),
# np.sin(alpha) * np.sin(beta) * np.sin(gamma) + np.cos(alpha) * np.cos(gamma),
# np.sin(alpha) * np.sin(beta) * np.sin(gamma) - np.cos(alpha) * np.sin(gamma)],
# [-np.sin(beta),
# np.cos(beta) * np.sin(gamma),
# np.cos(beta) * np.cos(gamma)]], dtype=np.float32)
# focal_position = (np.dot(focal_position, rotation_matrix))
# self.camera.SetPosition(focal_position)
# self.camera.SetViewUp(1,-1,0)
# self.camera.GetViewUp()
# self.camera.OrthogonalizeViewUp()
# self.camera.Roll(90)
iren = obj
iren.GetRenderWindow().Render()
self.timer_count += 1
self.imageFilter.Modified()
self.writer.Write()
if __name__ == "__main__":
from ImageReader import RawDataSetter
from Quantification import FactorQuantificationFromUniformPhantom
filepath = "C:\\Users\\pedro\\OneDrive - Universidade de Aveiro\\SimulacoesGATE\\EasyPET3D64\\NEMA-NU-4-2008-IQ\\15-December-2022ListMode\\whole_body\\ID_26 Jan 2022 - 00h 16m 02s_1p80bot_ IMAGE (71, 71, 129).T"
filepath = "C:\\Users\\pedro\\OneDrive - Universidade de Aveiro\\SimulacoesGATE\\EasyPET3D64\\NEMA-NU-4-2008-IQ\\15-December-2022ListMode\\Data articles\\gpu_article\\IQ\\OD-RT varying FWHM\\iterations\\EasyPETScan_it20_sb0"
filepath = "C:\\Users\\pedro\\OneDrive - Universidade de Aveiro\\SimulacoesGATE\\EasyPET3D64\\NEMA-NU-4-2008-IQ\\15-December-2022ListMode\\Data articles\\gpu_article\\IQ\\TOR\\iterations\\EasyPETScan_it20_sb0"
filepath = "C:\\Users\\pedro\\OneDrive - Universidade de Aveiro\\ICNAS\\Acquisitions 2022\\Easypet Scan 16 May 2022 - 10h 16m 52s\\whole_body\\ID_16 May 2022 - 10h 16m 52s_None_ IMAGE (71, 71, 129).T"
filepath = "C:\\Users\\pedro\\OneDrive - Universidade de Aveiro\\ICNAS\\Acquisitions 2022\\Easypet Scan 16 May 2022 - 10h 16m 52s\\whole_body\\ID_16 May 2022 - 10h 16m 52s_None_ IMAGE (71, 71, 129)_bestODRTVF.T"
filepath = "C:\\Users\\pedro\\OneDrive - Universidade de Aveiro\\ICNAS\\Acquisitions 2022\\Easypet Scan 16 May 2022 - 10h 16m 52s\\whole_body\\ID_16 May 2022 - 10h 16m 52s_None_ IMAGE (89, 89, 161).T"
filepath = "C:\\Users\\pedro\\OneDrive - Universidade de Aveiro\\ICNAS\\Acquisitions 2022\\Easypet Scan 16 May 2022 - 10h 16m 52s\\whole_body\\ID_16 May 2022 - 10h 16m 52s_None_ IMAGE (89, 89, 161)_32corrected_ODRTVF.T"
filepath = "C:\\Users\\pedro\\OneDrive - Universidade de Aveiro\\ICNAS\\Acquisitions 2022\\Easypet Scan 16 May 2022 - 10h 16m 52s\\whole_body\\ID_16 May 2022 - 10h 16m 52s_None_ IMAGE (118, 118, 216).T"
# filepath = "C:\\Users\\pedro\\OneDrive - Universidade de Aveiro\\ICNAS\\Acquisitions 2022\\Easypet Scan 16 May 2022 - 10h 16m 52s\\whole_body\\ID_16 May 2022 - 10h 16m 52s_None_ IMAGE (89, 89, 161)_32corrected_TOR.T"
# filepath = "C:\\Users\\pedro\\OneDrive - Universidade de Aveiro\\ICNAS\\Acquisitions 2022\\Easypet Scan 16 May 2022 - 10h 16m 52s\\whole_body\\ID_16 May 2022 - 10h 16m 52s_None_ IMAGE (89, 89, 161)_32corrected_ODRT.T"
# filepath = "C:\\Users\\pedro\\OneDrive - Universidade de Aveiro\\ICNAS\\Acquisitions 2022\\Easypet Scan 16 May 2022 - 10h 16m 52s\\whole_body\\ID_16 May 2022 - 10h 16m 52s_None_ IMAGE (89, 89, 161).T"
# filepath ="C:\\Users\\pedro\\OneDrive - Universidade de Aveiro\\SimulacoesGATE\EasyPET3D64\\NEMA-NU-4-2008-IQ\\15-December-2022ListMode\\Data articles\\gpu_article\\IQ\\TOR\\iterations\\EasyPETScan_it28_sb0"
filepath = "C:\\Users\\pedro\\OneDrive\\Ambiente de Trabalho\\DESKTOP Organizar\\GPU article\\ODTR\\Derenzo\\ID_26 Jan 2022 - 00h 16m 02s_GammasBackToBack.npy_ IMAGE (176, 176, 321).T"
filepath = "C:\\Users\\pedro\\OneDrive\\Ambiente de Trabalho\\DESKTOP Organizar\\GPU article\\TOR\\Derenzo\\ID_26 Jan 2022 - 00h 16m 02s_GammasBackToBack.npy_ IMAGE (176, 176, 321) .T"
# filepath = "C:\\Users\\pedro\\OneDrive\\Ambiente de Trabalho\\DESKTOP Organizar\\GPU article\\ODTRVF\\Derenzo\\ID_26 Jan 2022 - 00h 16m 02s_GammasBackToBack.npy_ IMAGE (176, 176, 321).T"
# filepath = "C:\\Users\\pedro\\OneDrive - Universidade de Aveiro\\ICNAS\\Acquisitions 2022\\Easypet Scan 16 May 2022 - 10h 16m 52s\\iterations\\EasyPETScan_it24_sb0"
# filepath = "C:\\Users\\pedro\\OneDrive - Universidade de Aveiro\\ICNAS\\Acquisitions 2022\\Easypet Scan 16 May 2022 - 10h 16m 52s\\\Data article\\ODRT\\EasyPETScan_it28_sb0"
# filepath = "C:\\Users\\pedro\\OneDrive\\Ambiente de Trabalho\\DESKTOP Organizar\\GPU article\\ODTRVF\\Mice\\ID_16 May 2022 - 10h 16m 52s_None_ IMAGE (118, 118, 216)_article.T"
# filepath = "C:\\Users\\pedro\\OneDrive - Universidade de Aveiro\\ICNAS\\Acquisitions 2022\\Easypet Scan 16 May 2022 - 10h 16m 52s\\iterations\\EasyPETScan_it28_sb0"
# filepath = "C:\\Users\\pedro\\OneDrive\\Ambiente de Trabalho\\Images intro\\Cu64\\MRI_Cu64_7_Dec_00h48"
# filepath = "C:\\Users\\pedro\\OneDrive\\Ambiente de Trabalho\\Images intro\\FDG_cardiac\\ID_06 Jul 2023 - 12h 29m 51s_Test Slow_ IMAGE (89, 89, 161).T"
size_file_m = [129, 129, 216]
size_file_m = [129, 129, 161]
size_file_m = [118, 118, 216]
# size_file_m = [89, 89, 161]
# size_file_m = [200, 400,50]
# size_file_m = [71, 71, 124]
# size_file_m = [71, 71, 129]
size_file_m = [176, 176, 321]
# size_file_m = [104,104,129]
# size_file_m = [78,78,129]
# size_file_m = [53,53,65]
r = RawDataSetter(filepath, size_file_m=size_file_m)
# r = RawDataSetter(filepath)
r.read_files(type_file="float32", big_endian=True)
voxeldata = r.volume
# set to zero the pixels in which the neighbor is much lo
# voxeldata[:, :, -2:] = 0
# voxeldata[:, :, :2] = 0
v_lim = np.array([0.02, 0.8])
scale_x = float(0.2)
scale_y = float(0.2)
scale_z = float(0.2 / (0.4 / 0.44))
#mri
# scale_x = 0.225
# scale_y = 0.5
# scale_z = 0.2
extent_x_y = [-scale_x * voxeldata.shape[0] / 2, scale_x * voxeldata.shape[0] / 2,
-scale_y * voxeldata.shape[1] / 2, scale_y * voxeldata.shape[1] / 2]
# generate coordinates
height = r.size_file_m[0]
width = r.size_file_m[1]
x = np.arange(0, width)
y = np.arange(0, width)
xx, yy = np.meshgrid(x, y)
quantification = FactorQuantificationFromUniformPhantom(voxel_volume=scale_x * scale_y * scale_z*0.001)
quantification.load_info()
quantification_factor = quantification.quantification_factor
print(quantification_factor)
quantification_factor=0.011
acquisition_time = 6586.2*7.2 #F18 half-life 109.77 min and in s 6586.2
voxel_volume = scale_x * scale_y * scale_z*0.001
# voxeldata = voxeldata / (acquisition_time * voxel_volume)
# voxeldata/=1*(10**6)
# voxeldata *= quantification_factor
# actidade Media
#mice
# voxeldata = voxeldata/(381*37000/17.33)
root = tk.Tk()
#derenzo
voxeldata = np.flip(voxeldata, axis=0)
viewer = SliceViewer(root, data3D=voxeldata, scale_x=scale_x, scale_y=scale_y, scale_z=scale_z, colormap="hot.cl")
#Nema
# viewer.setColorMapLimits(v_lim=[20, 1080])
# viewer.setZoomVolume(2)
# viewer.setVolumeRotation(90, 75, 60)
# # viewer.setMaxValueForVolume(300*37000/22/(1*10**6))
# viewer.NemaIQ2008(file_to_save="../../outputs/NemaIQ2008_renderTOR", only_scalar_bar=False)
# viewer.NemaIQ2008(file_to_save="../../outputs/NemaIQ2008_colorbar", only_scalar_bar=True)
# mice
# name_to_record ="../../outputs/MiceNAF_test_{}".format(os.path.basename(os.path.dirname(os.path.dirname(filepath))).split(".")[0].split("_")[-1])
# only_scalar_bar = False
# viewer.setColorMapLimits(v_lim=[10,750]) # 40, 750
# viewer.setZoomVolume(1.4)
# viewer.setVolumeRotation(0, -80, 10)
# viewer.setMaxValueForVolume(14)
# viewer.MiceNaf(filename=name_to_record, only_scalar_bar=only_scalar_bar, render_volume=True, recalculate_max_value=True)
#
# # # add masked image in the same window
# maskFilename = "../../outputs/mask_skull_name.png"
#
# # using PIL
# if only_scalar_bar is not True:
# from PIL import Image, ImageDraw
# # image_mask = Image.open(maskFilename)
# image = Image.open(name_to_record + ".png")
# image.convert("RGBA")
# # canvas = Image.new('RGBA', image.size, color="#") # Empty canvas colour (r,g,b,a)
# #new canvas with black background
# canvas = Image.new('RGB', image.size, color="#000000")
# #black background
# background = np.zeros((image.size[1], image.size[0], 3), dtype=np.uint8)
# maskedImage = Image.open(maskFilename)
# maskedImage.convert("RGBA")
#
# canvas.paste(image, mask=image) # Paste the image onto the canvas, using it's alpha channel as mask
# canvas.paste(maskedImage, mask=maskedImage) # Paste the image onto the canvas, using it's alpha channel as mask
# canvas.save(name_to_record + "_mask.png", resolution=300.0)
# viewer.createMovie(filename=name_to_record+".avi")
#Derenzo
viewer.setColorMapLimits(v_lim=[75, 1080])
viewer.setZoomVolume(2.5)
view = "37.5"
# view = "axial"
if view == "axial":
viewer.setVolumeRotation(90, -90, 90)
elif view == "37.5":
viewer.setVolumeRotation(90, -90, 37.5)
outputFilename = "../../outputs/Derenzo_{}_view_{}".format(os.path.basename(os.path.dirname(os.path.dirname(filepath))), view)
print(outputFilename)
viewer.derenzo(outputFilename=outputFilename)
root.mainloop()