Skip to content

Commit

Permalink
Merge branch 'master' into raw_dialog
Browse files Browse the repository at this point in the history
  • Loading branch information
lauramurgatroyd authored Dec 18, 2024
2 parents 58d3ae7 + 076cfb9 commit 2db3fcf
Show file tree
Hide file tree
Showing 11 changed files with 117 additions and 74 deletions.
43 changes: 22 additions & 21 deletions Wrappers/Python/ccpi/viewer/CILViewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ def __init__(self, callback):
#self.AddObserver('RightButtonPressEvent', self.OnRightMousePress, -0.5)
#self.AddObserver('RightButtonReleaseEvent', self.OnRightMouseRelease, -0.5)
self.htext = None
self.htext = None

def GetSliceOrientation(self):
return self._viewer.sliceOrientation
Expand Down Expand Up @@ -325,7 +324,7 @@ def DisplayHelp(self):
self.Render()
return

font_size = 24
font_size = 16

# Create the text mappers and the associated Actor2Ds.

Expand All @@ -342,25 +341,27 @@ def DisplayHelp(self):
# The text is on multiple lines and center-justified (both horizontal and
# vertical).
textMapperC = vtk.vtkTextMapper()
textMapperC.SetInput("Mouse Interactions:\n"
"\n"
" - Slice: Mouse Scroll\n"
" - Zoom: Right Mouse + Move Up/Down\n"
" - Pan: Middle Mouse Button + Move or Shift + Left Mouse + Move\n"
" - Adjust Camera: Left Mouse + Move\n"
" - Rotate: Ctrl + Left Mouse + Move\n"
"\n"
"Keyboard Interactions:\n"
"\n"
"h: Display this help\n"
"x: YZ Plane\n"
"y: XZ Plane\n"
"z: XY Plane\n"
"r: Save render to current_render.png\n"
"s: Toggle visibility of slice\n"
"v: Toggle visibility of volume render\n"
"c: Activates volume render clipping plane widget\n"
"a: Whole image Auto Window/Level\n")
if self.htext == None:
self.htext = """
Mouse Interactions:
- Slice: Mouse Scroll
- Zoom: Right Mouse + Move Up/Down
- Pan: Middle Mouse Button + Move or Shift + Left Mouse + Move
- Adjust Camera: Left Mouse + Move
- Rotate: Ctrl + Left Mouse + Move
Keyboard Interactions:
h: Display this help
x: YZ Plane
y: XZ Plane
z: XY Plane
r: Save render to current_render.png
s: Toggle visibility of slice
v: Toggle visibility of volume render
c: Activates volume render clipping plane widget
a: Whole image Auto Window/Level
"""
textMapperC.SetInput(self.htext)
tprop = textMapperC.GetTextProperty()
tprop.ShallowCopy(multiLineTextProp)
tprop.SetJustificationToLeft()
Expand Down
72 changes: 42 additions & 30 deletions Wrappers/Python/ccpi/viewer/CILViewer2D.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def __init__(self, callback):
self.dy = 0

self._reslicing_enabled = True
self.htext = None

@property
def reslicing_enabled(self):
Expand Down Expand Up @@ -896,7 +897,7 @@ def DisplayHelp(self):
self.Render()
return

font_size = 24
font_size = 16

# Create the text mappers and the associated Actor2Ds.

Expand All @@ -913,33 +914,36 @@ def DisplayHelp(self):
# The text is on multiple lines and center-justified (both horizontal and
# vertical).
textMapperC = vtk.vtkTextMapper()
textMapperC.SetInput("Mouse Interactions:\n"
"\n"
" - Slice: Mouse Scroll\n"
" - Quick Slice: Shift + Mouse Scroll\n"
" - Pick: Left Click\n"
" - Zoom: Shift + Right Mouse + Move Up/Down\n"
" - Pan: Ctrl + Right Mouse + Move\n"
" - Adjust Window: Alt+ Right Mouse + Move Up/Down\n"
" - Adjust Level: Alt + Right Mouse + Move Left/Right\n"
" Region of Interest (ROI):\n"
" - Create: Ctrl + Left Click\n"
" - Delete: Alt + Left Click\n"
" - Resize: Click + Drag handles\n"
" - Translate: Middle Mouse + Move within ROI\n"
"\n"
"Keyboard Interactions:\n"
"\n"
" - a: Whole image Auto Window/Level\n"
" - w: Region around cursor Auto Window/Level\n"
" - l: Line Profile at cursor\n"
" - s: Save Current Image\n"
" - x: YZ Plane\n"
" - y: XZ Plane\n"
" - z: XY Plane\n"
" - t: Tracing\n"
" - i: toggle interpolation of slice\n"
" - h: this help\n")
if self.htext == None:
self.htext = """
Mouse Interactions:
- Slice: Mouse Scroll
- Quick Slice: Shift + Mouse Scroll
- Pick: Left Click
- Zoom: Shift + Right Mouse + Move Up/Down
- Pan: Ctrl + Right Mouse + Move
- Adjust Window: Alt+ Right Mouse + Move Up/Down
- Adjust Level: Alt + Right Mouse + Move Left/Right
Region of Interest (ROI):
- Create: Ctrl + Left Click
- Delete: Alt + Left Click
- Resize: Click + Drag handles
- Translate: Middle Mouse + Move within ROI
Keyboard Interactions:
h: This help
x: YZ Plane
y: XZ Plane
z: XY Plane
a: Whole image Auto Window/Level
w: Region around cursor Auto Window/Level
l: Line Profile at cursor
s: Save Current Image
t: Tracing
i: Toggle interpolation of slice
"""
textMapperC.SetInput(self.htext)
tprop = textMapperC.GetTextProperty()
tprop.ShallowCopy(multiLineTextProp)
tprop.SetJustificationToLeft()
Expand Down Expand Up @@ -1550,11 +1554,18 @@ def installSliceSliderWidgetPipeline(self):
'''Create the pipeline for the slice slider widget
The slider widget and representation are created if not already present.
Currently the slider widget enabled flag is not used.
If present, the slider is updated.
The slider is hidden if any of the dimensions of the visualised image is 1,
else it is shown.
'''
# set slider_hidden
dims = self.img3D.GetDimensions()
slider_hidden = any(dim == 1 for dim in dims)

if self.sliderWidget is not None:
# reset the values to the appropriate ones of the new loaded image
self.sliderCallback.update_orientation(self.style, 'reset')
self.sliderWidget.SetEnabled(not slider_hidden)
return

sr = SliceSliderRepresentation()
Expand All @@ -1567,7 +1578,8 @@ def installSliceSliderWidgetPipeline(self):
sw.SetRepresentation(sr)
sw.SetAnimationModeToAnimate()
sw.EnabledOn()

# enable slider
sw.SetEnabled(not slider_hidden)
cb = SliderCallback(self, sw)

# Add interaction observers
Expand Down
6 changes: 3 additions & 3 deletions Wrappers/Python/ccpi/viewer/iviewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class SingleViewerCenterWidget(QtWidgets.QMainWindow):
def __init__(self, parent=None, viewer=viewer2D):
QtWidgets.QMainWindow.__init__(self, parent)

self.frame = QCILViewerWidget(viewer=viewer, shape=(600, 600))
self.frame = QCILViewerWidget(parent, viewer=viewer, shape=(600, 600))

if viewer == viewer3D:
self.frame.viewer.setVolumeRenderOpacityMethod('scalar')
Expand All @@ -41,8 +41,8 @@ def __init__(self, parent=None, viewer1='2D', viewer2='2D'):
elif viewer == '3D':
styles.append(vlink.Linked3DInteractorStyle)
viewers.append(eval('viewer' + viewer))
self.frame1 = QCILViewerWidget(viewer=viewers[0], shape=(600, 600), interactorStyle=styles[0])
self.frame2 = QCILViewerWidget(viewer=viewers[1], shape=(600, 600), interactorStyle=styles[1])
self.frame1 = QCILViewerWidget(parent, viewer=viewers[0], shape=(600, 600), interactorStyle=styles[0])
self.frame2 = QCILViewerWidget(parent, viewer=viewers[1], shape=(600, 600), interactorStyle=styles[1])

# Initially link viewers
self.linkedViewersSetup()
Expand Down
2 changes: 0 additions & 2 deletions Wrappers/Python/ccpi/viewer/ui/main_windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
import sys
from functools import partial
from pathlib import Path

import ccpi.viewer.viewerLinker as vlink
import vtk
from ccpi.viewer import CILViewer2D, CILViewer
Expand Down Expand Up @@ -381,7 +380,6 @@ def updateViewerCoordsDockWidgetWithCoords(self, reader=None):
The reader used to read the image. This contains some extra info about the
original image file.
'''

viewer = self.viewer_coords_dock.viewers[0]

if not isinstance(viewer, (CILViewer2D, CILViewer)):
Expand Down
35 changes: 23 additions & 12 deletions Wrappers/Python/ccpi/viewer/utils/conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,24 +90,31 @@ class Converter(object):

@staticmethod
def numpy2vtkImage(nparray, spacing=(1., 1., 1.), origin=(0, 0, 0), deep=0, output=None):
"""The method converts a numpy array to a vtk image.
The vtk extent is set and needs to differentiate between 3D and 2D images."""
"""
The method converts a numpy array to a vtk image.
Raises an error if the dimension of the image is not 2 or 3.
The array is flattened in the correct order, either fortran or C.
The vtk extent is set and needs to differentiate between 3D and 2D images.
Creates a vtkImageData if `output` is None, otherwise uses the provided empty output.
Adds the vtkarray to the image's point data. If an array is already present, it removes it."""

shape = numpy.shape(nparray)
if (nparray.flags["FNC"]):
num_dims = len(shape)
if num_dims not in [2, 3]:
raise ValueError("Only 2D or 3D numpy arrays are supported.")

if nparray.flags["FNC"]:
order = "F"
i = 0
k = len(shape) - 1
i, k = 0, num_dims - 1
else:
order = "C"
i = len(shape) - 1
k = 0
i, k = num_dims - 1, 0

nparray = nparray.ravel(order)
vtkarray = numpy_support.numpy_to_vtk(num_array=nparray,
deep=deep,
array_type=numpy_support.get_vtk_array_type(nparray.dtype))
vtkarray.SetName('vtkarray')

if output is None:
img_data = vtk.vtkImageData()
Expand All @@ -117,12 +124,16 @@ def numpy2vtkImage(nparray, spacing=(1., 1., 1.), origin=(0, 0, 0), deep=0, outp
else:
img_data = output

img_data.GetPointData().AddArray(vtkarray)
if len(shape) == 3:
point_data = img_data.GetPointData()
while point_data.GetNumberOfArrays() > 0:
point_data.RemoveArray(0)
vtkarray.SetName('ImageScalars')
point_data.AddArray(vtkarray)
img_data.GetPointData().SetScalars(vtkarray)
if num_dims == 3:
img_data.SetExtent(0, shape[i] - 1, 0, shape[1] - 1, 0, shape[k] - 1)
elif len(shape) == 2:
elif num_dims == 2:
img_data.SetExtent(0, shape[i] - 1, 0, shape[k] - 1, 0, 0)
img_data.GetPointData().SetActiveScalars('vtkarray')
img_data.SetOrigin(origin)
img_data.SetSpacing(spacing)

Expand Down
14 changes: 14 additions & 0 deletions Wrappers/Python/examples/2Dimage_reading.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from ccpi.viewer.CILViewer2D import CILViewer2D
import vtk

# This example imports a 2D tiff image and tests the 2D viewer
DATASET_TO_READ = [path] # insert path here
if DATASET_TO_READ is not None:
reader = vtk.vtkTIFFReader()
reader.SetFileName(DATASET_TO_READ)
reader.Update()

v = CILViewer2D()
print(reader.GetOutput())
v.setInputData(reader.GetOutput())
v.startRenderLoop()
3 changes: 2 additions & 1 deletion Wrappers/Python/examples/FourDockableLinkedViewerWidgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ def __init__(self, parent=None, reader=None):
#self.resize(800,600)

# create the dockable widgets with the viewer inside
self.v00 = QCILDockableWidget(viewer=viewer2D,
self.v00 = QCILDockableWidget(parent,
viewer=viewer2D,
shape=(600, 600),
title="X",
interactorStyle=vlink.Linked2DInteractorStyle)
Expand Down
2 changes: 1 addition & 1 deletion Wrappers/Python/examples/SingleViewerCentralWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class SingleViewerCenterWidget(QtWidgets.QMainWindow):
def __init__(self, parent=None, viewer=viewer2D):
QtWidgets.QMainWindow.__init__(self, parent)

self.frame = QCILViewerWidget(viewer=viewer, shape=(600, 600))
self.frame = QCILViewerWidget(parent, viewer=viewer, shape=(600, 600))

head = example_data.HEAD.get()

Expand Down
2 changes: 1 addition & 1 deletion Wrappers/Python/examples/SingleViewerCentralWidget2.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class SingleViewerCenterWidget(QtWidgets.QMainWindow):
def __init__(self, parent=None, viewer=viewer2D):
QtWidgets.QMainWindow.__init__(self, parent)
self.setGeometry(450, 250, 1000, 1000)
self.frame = QCILViewerWidget(viewer=viewer, shape=(2000, 2000))
self.frame = QCILViewerWidget(parent, viewer=viewer, shape=(2000, 2000))

head = example_data.HEAD.get()

Expand Down
10 changes: 8 additions & 2 deletions Wrappers/Python/examples/TwoLinkedViewersCentralWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,14 @@ def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
#self.resize(800,600)

self.frame1 = QCILViewerWidget(viewer=viewer2D, shape=(600, 600), interactorStyle=vlink.Linked2DInteractorStyle)
self.frame2 = QCILViewerWidget(viewer=viewer3D, shape=(600, 600), interactorStyle=vlink.Linked3DInteractorStyle)
self.frame1 = QCILViewerWidget(parent,
viewer=viewer2D,
shape=(600, 600),
interactorStyle=vlink.Linked2DInteractorStyle)
self.frame2 = QCILViewerWidget(parent,
viewer=viewer3D,
shape=(600, 600),
interactorStyle=vlink.Linked3DInteractorStyle)

head = example_data.HEAD.get()

Expand Down
2 changes: 1 addition & 1 deletion Wrappers/Python/examples/opacity_in_viewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class OpacityViewerWidget(SingleViewerCenterWidget):
def __init__(self, parent=None, viewer=viewer3D):
SingleViewerCenterWidget.__init__(self, parent)

self.frame = QCILViewerWidget(viewer=viewer, shape=(600, 600))
self.frame = QCILViewerWidget(parent, viewer=viewer, shape=(600, 600))

self.setCentralWidget(self.frame)

Expand Down

0 comments on commit 2db3fcf

Please sign in to comment.