def __init__(self, vol, a_transversal, a_coronal, a_sagittal, a_text): # Create text objects self._labelx = vv.Label(a_text) self._labely = vv.Label(a_text) self._labelz = vv.Label(a_text) self._labelx.position = 10, 10 self._labely.position = 10, 30 self._labelz.position = 10, 50 # Create Finish button self._finished = False self._but = vv.PushButton(a_text) self._but.position = 10, 80 self._but.text = 'Finish' # Get short name for sampling if isinstance(vol, Aarray): self._sam = sam = vol.sampling else: self._sam = None sam = (1, 1, 1) # Calculate mips and deal with anisotropy mipz = np.max(vol, 0) mipz = Aarray(mipz, (sam[1], sam[2])) mipy = np.max(vol, 1) mipy = Aarray(mipy, (sam[0], sam[2])) mipx = np.max(vol, 2) mipx = Aarray(mipx, (sam[0], sam[1])) # Display the mips vv.imshow(mipz, axes=a_transversal) vv.imshow(mipy, axes=a_coronal) vv.imshow(mipx, axes=a_sagittal) # Initialize range objects self._range_transversal = RangeWobject2D(a_transversal, mipz) self._range_coronal = RangeWobject2D(a_coronal, mipy) self._range_sagittal = RangeWobject2D(a_sagittal, mipx) # Get list of all range wobjects self._rangeWobjects = [ self._range_transversal, self._range_coronal, self._range_sagittal ] # Bind events fig = a_text.GetFigure() fig.eventClose.Bind(self._OnFinish) self._but.eventPress.Bind(self._OnFinish) for r in self._rangeWobjects: r.eventRangeUpdated.Bind(self._OnRangeUpdated) # Almost done self._SetTexts()
def add_label(text, pos, angle=0, fontName=None, fontSize=9, color='k', bgcolor=None, axes=None): ''' Adds a label inside the axes. Returns the Label object. Parameters: text - String. The text of the label pos - Tuple with two numbers. The (x,y) position of the label with origin at the upper left corner. angle - Float or int. The rotation of the label in degrees. fontname- String. Either 'mono', 'sans' or 'serif'. fontSize- Int. Size of the text. Default 9. color - A 3-tuple or a character in 'rgbycmkw', etc that defines text color. Default 'k' (black). bgcolor - Background color. See color. Default None. axes - Axes wherein the label is placed. If None then the current axes is chosen. ''' if axes is None: axes = vv.gca() label = vv.Label(axes, text, fontName, fontSize, color) label.position = pos label.bgcolor = bgcolor label.textAngle = angle return label
def __init__(self, im, grid_sampling=40): # Store image self._im = im # Setup visualization self._fig = fig = vv.figure() self._a1 = a1 = vv.subplot(231); self._a2 = a2 = vv.subplot(232); self._a3 = a3 = vv.subplot(233); self._a4 = a4 = vv.subplot(234); self._a5 = a5 = vv.subplot(235); self._a6 = a6 = vv.subplot(236); # Text objects self._text1 = vv.Label(fig) self._text1.position = 5, 2 self._text2 = vv.Label(fig) self._text2.position = 5, 20 # Move axes a1.parent.position = 0.0, 0.1, 0.33, 0.45 a2.parent.position = 0.33, 0.1, 0.33, 0.45 a3.parent.position = 0.66, 0.1, 0.33, 0.45 a4.parent.position = 0.0, 0.55, 0.33, 0.45 a5.parent.position = 0.33, 0.55, 0.33, 0.45 a6.parent.position = 0.66, 0.55, 0.33, 0.45 # Correct axes, share camera cam = vv.cameras.TwoDCamera() for a in [a1, a2, a3, a4, a5, a6]: a.axis.visible = False a.camera = cam # Show images im0 = im*0 self._t1 = vv.imshow(im, axes=a1) self._t2 = vv.imshow(im, axes=a2) self._t3 = vv.imshow(im, axes=a3) self._t4 = vv.imshow(im0, axes=a4) self._t5 = vv.imshow(im0, axes=a5) self._t6 = vv.imshow(im0, axes=a6) # Init pointsets self._pp1 = Pointset(2) self._pp2 = Pointset(2) self._active = None self._lines = [] # Init lines to show all deformations tmp = vv.Pointset(2) self._line1 = vv.plot(tmp, ls='', ms='.', mc='c', axes=a2) self._line2 = vv.plot(tmp, ls='+', lc='c', lw='2', axes=a2) # Init grid properties self._sampling = grid_sampling self._levels = 5 self._multiscale = True self._injective = 0.5 self._frozenedge = 1 self._forward = True # Init grid self.DeformationField = DeformationFieldForward self._field1 = self.DeformationField(FieldDescription(self._im)) self._field2 = self.DeformationField(FieldDescription(self._im)) # Bind to events a2.eventMouseDown.Bind(self.on_down) a2.eventMouseUp.Bind(self.on_up) a2.eventMotion.Bind(self.on_motion) fig.eventKeyDown.Bind(self.on_key_down) #a1.eventDoubleClick.Bind(self.OnDone) # Apply self.apply()
f.position = 968.00, 30.00, 944.00, 1002.00 a = vv.gca() show_ctvolume(vol, model, showVol=showVol, clim=clim0, isoTh=isoTh) model.Draw(mc='b', mw = 10, lc='g') vv.xlabel('x (mm)');vv.ylabel('y (mm)');vv.zlabel('z (mm)') vv.title('Analysis for model LSPEAS %s - %s' % (ptcode[7:], ctcode)) a.axis.axisColor= 1,1,1 a.bgcolor= 0,0,0 a.daspect= 1, 1, -1 # z-axis flipped a.axis.visible = showAxis # Initialize labels GUI from visvis import Pointset from stentseg.stentdirect import stentgraph t1 = vv.Label(a, 'Edge ctvalue: ', fontSize=11, color='c') t1.position = 0.1, 5, 0.5, 20 # x (frac w), y, w (frac), h t1.bgcolor = None t1.visible = False t2 = vv.Label(a, 'Edge cost: ', fontSize=11, color='c') t2.position = 0.1, 25, 0.5, 20 t2.bgcolor = None t2.visible = False t3 = vv.Label(a, 'Edge length: ', fontSize=11, color='c') t3.position = 0.1, 45, 0.5, 20 t3.bgcolor = None t3.visible = False #Add clickable nodes node_points = _utils_GUI.interactive_node_points(model)
def __init__(self, dirsave, ptcode, ctcode, cropname, s, what='phases', axes=None, **kwargs): """ s is struct from loadvol """ self.fig = vv.figure(1) vv.clf() self.fig.position = 0.00, 29.00, 1680.00, 973.00 self.defaultzoom = 0.025 # check current zoom with foo.ax.GetView() self.what = what self.ptcode = ptcode self.dirsave = dirsave self.ctcode = ctcode self.cropname = cropname if self.what == 'phases': self.phase = 0 else: self.phase = self.what # avgreg # self.vol = s.vol0 self.s = s # s with vol(s) self.s_landmarks = vv.ssdf.new() self.graph = stentgraph.StentGraph() self.points = [] # selected points self.nodepoints = [] self.pointindex = 0 # for selected points try: self.vol = s.vol0 # when phases except AttributeError: self.vol = s.vol # when avgreg self.ax = vv.subplot(121) self.axref = vv.subplot(122) self.label = DrawModelAxes(self.vol, ax=self.ax) # label of clicked point self.axref.bgcolor = 0, 0, 0 self.axref.visible = False # create axis for buttons a_select = vv.Wibject(self.ax) # on self.ax or fig? a_select.position = 0.55, 0.7, 0.6, 0.5 # x, y, w, h # Create text objects self._labelcurrentIndexT = vv.Label(a_select) # for text title self._labelcurrentIndexT.position = 125, 180 self._labelcurrentIndexT.text = ' Total selected =' self._labelcurrentIndex = vv.Label(a_select) self._labelcurrentIndex.position = 225, 180 # Create Select button self._select = False self._butselect = vv.PushButton(a_select) self._butselect.position = 10, 150 self._butselect.text = 'Select' # Create Back button self._back = False self._butback = vv.PushButton(a_select) self._butback.position = 125, 150 self._butback.text = 'Undo' # Create Next/Save button self._finished = False self._butclose = vv.PushButton(a_select) self._butclose.position = 10, 230 self._butclose.text = 'Next/Save' # # Create Save landmarks button # self._save = False # self._butsave = vv.PushButton(a_select) # self._butsave.position = 125,230 # self._butsave.text = 'Save|Finished' # Create Reset-View button self._resetview = False self._butresetview = vv.PushButton(a_select) self._butresetview.position = 10, 180 self._butresetview.text = 'Default Zoom' # back to default zoom # bind event handlers self.fig.eventClose.Bind(self._onFinish) self._butclose.eventPress.Bind(self._onFinish) self._butselect.eventPress.Bind(self._onSelect) self._butback.eventPress.Bind(self._onBack) self._butresetview.eventPress.Bind(self._onView) # self._butsave.eventPress.Bind(self._onSave) self._updateTextIndex() self._updateTitle()
fig = vv.figure(); vv.clf() fig.position = 9.00, 30.00, 944.00, 1002.00 a = vv.gca() label = DrawModelAxes(vol, model, a, getLabel=True, clim=clim, showVol=showVol, mw=10) vv.title('Model for LSPEAS %s - %s' % (ptcode[7:], ctcode)) viewAP = {'zoom': 0.006,'fov': 0.0, 'daspect': (1.0, 1.0, -1.0), 'azimuth': 0.0, 'roll': 0.0} # Set view # a.SetView(viewAP) # Initialize labels t0 = vv.Label(a, '\b{Node nr|location}: ', fontSize=11, color='w') t0.position = 0.1, 25, 0.5, 20 # x (frac w), y, w (frac), h t0.bgcolor = None t0.visible = True t1 = vv.Label(a, '\b{Nodepair}: ', fontSize=11, color='w') t1.position = 0.1, 45, 0.5, 20 # x (frac w), y, w (frac), h t1.bgcolor = None t1.visible = False t2 = vv.Label(a, 'Node-to-node Min: ', fontSize=11, color='w') t2.position = 0.1, 65, 0.5, 20 t2.bgcolor = None t2.visible = False t3 = vv.Label(a, 'Node-to-node Max: ', fontSize=11, color='w') t3.position = 0.1, 85, 0.5, 20 t3.bgcolor = None t3.visible = False
def __init__(self, vol, a_transversal, a_coronal, a_sagittal, a_MIP, a_text, nr_of_stents, clim=None): self.nr_of_stents = nr_of_stents self.f = vv.gcf() self.vol = vol # Create empty list of endpoints self.endpoints = [] self.endpoints = ['xx,yy,zz'] * nr_of_stents * 2 self.endpointsindex = 0 # Create text objects self._labelcurrent = vv.Label(a_text) self._labelx = vv.Label(a_text) self._labelxslice = vv.Label(a_text) self._labely = vv.Label(a_text) self._labelyslice = vv.Label(a_text) self._labelz = vv.Label(a_text) self._labelzslice = vv.Label(a_text) self._labelcurrent.position = -250, 10 self._labelx.position = -250, 35 self._labelxslice.position = -200, 35 self._labely.position = -250, 55 self._labelyslice.position = -200, 55 self._labelz.position = -250, 75 self._labelzslice.position = -200, 75 self._labelendpointstext = [] self._labelendpointstext.append(vv.Label(a_text)) self._labelendpointstext[0].position = 100, -5 self._labelendpointstext.append(vv.Label(a_text)) self._labelendpointstext[1].position = 230, -5 for i in range(2, self.nr_of_stents + 2): self._labelendpointstext.append(vv.Label(a_text)) self._labelendpointstext[i].position = 40, 15 + (20 * (i - 2)) self._labelendpoints = [] for i in range(0, self.nr_of_stents * 2, 2): self._labelendpoints.append(vv.Label(a_text)) self._labelendpoints[i].position = 100, 15 + (20 * (i / 2)), 50, 20 self._labelendpoints.append(vv.Label(a_text)) self._labelendpoints[i + 1].position = 230, 15 + (20 * (i / 2)), 50, 20 # Create Select button self._select = False self._butselect = vv.PushButton(a_text) self._butselect.position = -110, 150 self._butselect.text = 'Select' # Create Back button self._back = False self._butback = vv.PushButton(a_text) self._butback.position = 10, 150 self._butback.text = 'Back' # Create Close button self._finished = False self._butclose = vv.PushButton(a_text) self._butclose.position = -50, 180 self._butclose.text = 'Finish' # Get short name for sampling if isinstance(vol, Aarray): self._sam = sam = vol.sampling else: self._sam = None sam = (1, 1, 1) # Display the slices and 3D MIP self.b1 = VolViewer(vol, 0, axes=a_transversal, clim=clim) self.b2 = VolViewer(vol, 1, axes=a_coronal, clim=clim) self.b3 = VolViewer(vol, 2, axes=a_sagittal, clim=clim) renderstyle = 'mip' a_MIP.daspect = 1, 1, -1 self.b4 = vv.volshow(vol, clim=(0, 2500), renderStyle=renderstyle, axes=a_MIP) c = vv.ClimEditor(a_MIP) c.position = (10, 50) # set axis settings for a in [a_transversal, a_coronal, a_sagittal, a_MIP]: a.bgcolor = [0, 0, 0] a.axis.visible = False a.showAxis = True # get current slice number Zslice = self.b1.GetCurrentSlice() Yslice = self.b2.GetCurrentSlice() Xslice = self.b3.GetCurrentSlice() size = vol.shape # create lines for position of x,y and z slices origin = vol.origin Zrange = (origin[0], (size[0] * sam[0]) + origin[0]) Xrange = (origin[1], (size[1] * sam[1]) + origin[1]) Yrange = (origin[2], (size[2] * sam[2]) + origin[2]) self.l11 = vv.Line(a_transversal, [(Yslice, Xrange[0]), (Yslice, Xrange[1])]) self.l12 = vv.Line(a_transversal, [(Yrange[0], Xslice), (Yrange[1], Xslice)]) self.l21 = vv.Line(a_coronal, [(Zslice, Zrange[0]), (Zslice, Zrange[1])]) self.l22 = vv.Line(a_coronal, [(Yrange[0], Xslice), (Yrange[1], Xslice)]) self.l31 = vv.Line(a_sagittal, [(Zslice, Zrange[0]), (Zslice, Zrange[1])]) self.l32 = vv.Line(a_sagittal, [(Xrange[0], Yslice), (Xrange[1], Yslice)]) # change color of the lines for i in [self.l11, self.l12, self.l21, self.l22, self.l31, self.l32]: i.lc = 'g' # create a point in the MIP figure for the current position self.mippoint = vv.Line(a_MIP, [(Zslice, Xslice, Yslice)]) self.mippoint.ms = 'o' self.mippoint.mw = 5 self.mippoint.mc = 'g' self.mippoint.alpha = 0.9 # Get list of all range wobjects self._volviewers = [self.b1, self.b2, self.b3] # Bind events fig = a_text.GetFigure() fig.eventClose.Bind(self._OnFinish) self._butclose.eventPress.Bind(self._OnFinish) self._butselect.eventPress.Bind(self._OnSelect) self._butback.eventPress.Bind(self._OnBack) for r in self._volviewers: r.eventPositionUpdate.Bind(self._OnMouseClickAxis) for s in range(len(self._labelendpoints)): self._labelendpoints[s].eventMouseDown.Bind( self._OnMouseClickEndpoint) # Almost done self._SetTexts() self.updatePosition()
import visvis as vv # Create figure and figure fig = vv.figure() a = vv.cla() a.cameraType = '2d' a.daspectAuto = True a.SetLimits((0, 8), (-1, 10)) # Create text inside the axes vv.Text(a, 'These are texts living in the scene:', 1, 3) vv.Text(a, 'Text can be made \b{bold} easil\by!', 1, 2) vv.Text(a, 'Text can be made \i{italic} easil\iy!', 1, 1) # Create text labels label0 = vv.Label(a, 'These are texts in widget coordinates:') label0.position = 10, 20 label1 = vv.Label(a, 'Sub_{script} and super^{script} are easy as pi^2.') label1.position = 10, 40 label2 = vv.Label(a, u'You can use many Unicode characters: \\u0183 = \u0183') label2.position = 10, 60 label3 = vv.Label( a, 'And can use many Latex like commands: \\alpha \\Alpha' + '\\approx, \sigma, \pi, ') label3.position = 10, 80 for label in [label0, label1, label2, label3]: label.bgcolor = (0.5, 1, 0.5) label.position.w = 400 # Enter main loop
# Initialize 2D view axes2 = vv.Axes(vv.gcf()) axes2.position = 0.65, 0.05, 0.3, 0.4 axes2.daspectAuto = False axes2.camera = '2d' axes2.axis.showGrid = True axes2.axis.axisColor = 'k' # Initialize axes to put widgets and labels in container = vv.Wibject(vv.gcf()) container.position = 0.65, 0.5, 0.3, 0.5 # Create labels to show measurements labelpool = [] for i in range(16): label = vv.Label(container) label.fontSize = 11 label.position = 10, 100 + 25 * i, -20, 25 labelpool.append(label) # Initialize sliders and buttons slider_ref = vv.Slider(container, fullRange=(1, len(centerline) - 2), value=10) slider_ves = vv.Slider(container, fullRange=(1, len(centerline) - 2), value=10) button_go = vv.PushButton(container, "Take all measurements (incl. volume)") slider_ref.position = 10, 5, -20, 25 slider_ves.position = 10, 40, -20, 25 button_go.position = 10, 70, -20, 25 button_go.bgcolor = slider_ref.bgcolor = slider_ves.bgcolor = 0.8, 0.8, 1.0 # Initialize line objects for showing the plane orthogonal to centerline slider_ref.line_plane = vv.plot([], [], [],
def pick3d(axes, vol): """ Enable picking intensities in a 3D volume. Given an Axes object and a volume (an Aarray), will show the value, index and position of the voxel with maximum intentity under the cursor when doing a SHIFT+RIGHTCLICK. Returns the label object, so that it can be re-positioned. Assumptions: * ThreeDCamera is in use and in orthographic mode (no perspective). * The volume does not have any transformations w.r.t the axes, except for the implicit transformations defined by its sampling and origin. """ assert hasattr(vol, 'sampling'), 'Vol must be an Aarray.' line = vv.plot(vv.Pointset(3), ms='o', mw=12, lc='c', mc='c', alpha=0.4, axesAdjust=False) label = vv.Label(axes) label.position = 0, 0, 1, 20 @axes.eventMouseDown.Bind def onClick(event): if event.button == 2 and vv.KEY_SHIFT in event.modifiers: # Get clicked location in NDC w, h = event.owner.position.size x, y = 2 * event.x / w - 1, -2 * event.y / h + 1 # Apply inverse camera transform to get two points on the clicked line M = np.linalg.inv(get_camera_matrix(event.owner)) p1 = vv.Point(np.dot((x, y, -100, 1), M)[:3]) p2 = vv.Point(np.dot((x, y, +100, 1), M)[:3]) # Calculate center point and vector pm = 0.5 * (p1 + p2) vec = (p2 - p1).normalize() # Prepare for searching in two directions pp = [pm - vec, pm + vec] status = 0 if sample(vol, pm) is None else 1 status = [status, status] hit = None max_sample = -999999 step = min(vol.sampling) # Look in two directions simulaneously, search for volume, collect samples for i in range(10000): # Safe while-loop for j in (0, 1): if status[j] < 2: s = sample(vol, pp[j]) inside = s is not None if inside: if s > max_sample: max_sample, hit = s, pp[j] if status[j] == 0: status[j] = 1 status[ not j] = 2 # stop looking in other direction else: if status[j] == 1: status[j] = 2 pp[j] += (j * 2 - 1) * step * vec if status[0] == 2 and status[1] == 2: break else: print('Warning: ray casting to collect samples did not stop' ) # clicking outside the volume # Draw pp2 = vv.Pointset(3) text = 'No point inside volume selected.' if hit: pp2.append(hit) ii = vol.point_to_index(hit) text = 'At z=%1.1f, y=%1.1f, x=%1.1f -> X[%i, %i, %i] -> %1.2f' % ( hit.z, hit.y, hit.x, ii[0], ii[1], ii[2], max_sample) line.SetPoints(pp2) label.text = text return True # prevent default mouse action return label
t1 = vv.Text(a, 'Visvis text', 0.2, 9, 0, 'mono', 30) t2 = vv.Text(a, '... with FreeType!', 1, 8, 0, 'serif', 12) t3 = vv.Text(a, '... and Unicode: %s!' % hello, 1, 7) t3 = vv.Text( a, '\Gamma\rho\epsilon\epsilon\kappa letters and ' + ' \rightarrow math \otimes symbols', 1, 6) t2 = vv.Text( a, '\b{bold}, \i{italic}, and \b{\i{bolditalic}} \bfon\its' + ' and sup^{script} and sub_{script}', 1, 5, 0, 'serif') t3 = vv.Text(a, 'Look, I\'m at an angle!', 1, 4) t3.textAngle = -20 t3.fontSize = 12 # Create text labels label1 = vv.Label(a, 'This is a Label') label1.position = 10, 0.9 label1.bgcolor = (0.5, 1, 0.5) ## A quick brown fox jumps over the lazy dog testText = 'A quick brown fox jumps over the lazy dog' # Create figure and figure fig = vv.figure() a = vv.cla() a.cameraType = '2d' vv.title(testText) # Create text labels for i in range(20):
dm.clim = clim3 dm.colormap = vv.CM_JET #todo: use colormap Viridis or Magma as JET is not linear (https://bids.github.io/colormap/) vv.colorbar() else: dm.faceColor = 'g' # Run mesh a.SetLimits() # a.SetView(viewringcrop) dm.MotionPlay(motionPlay[0], motionPlay[1]) # (10, 0.2) = each 10 ms do a step of 20% for a phase dm.motionSplineType = 'B-spline' dm.motionAmplitude = 0.5 # 1 or less. For a mesh we can (more) safely increase amplitude #todo: dm.SetValues in loop for changing color? # Add clickable nodes t0 = vv.Label(a, 'Node nr|location: ', fontSize=11, color='w') t0.position = 0.01, 5, 0.5, 20 t0.bgcolor = None t0.visible = False if meshWithColors: t1 = vv.Label(a, 'Node amplitude XYZ: ', fontSize=11, color='w') t1.position = 0.01, 25, 0.5, 20 # x (frac w), y, w (frac), h t1.bgcolor = None t1.visible = False t2 = vv.Label(a, 'Node amplitude Z: ', fontSize=11, color='w') t2.position = 0.01, 45, 0.5, 20 t2.bgcolor = None t2.visible = False t3 = vv.Label(a, 'Node amplitude Y: ', fontSize=11, color='w') t3.position = 0.01, 65, 0.5, 20 t3.bgcolor = None
def __init__(self,ptcode,ctcode,allcenterlines,basedir): """ Script to show the stent plus centerline model and select points on centerlines for motion analysis """ import os, time import pirt import visvis as vv import numpy as np import math import itertools import xlsxwriter from datetime import datetime from stentseg.utils.datahandling import select_dir, loadvol, loadmodel from stentseg.utils.new_pointset import PointSet from stentseg.stentdirect.stentgraph import create_mesh from stentseg.motion.vis import create_mesh_with_abs_displacement from stentseg.utils.visualization import show_ctvolume from pirt.utils.deformvis import DeformableTexture3D, DeformableMesh from stentseg.utils import PointSet from stentseg.stentdirect import stentgraph from visvis import Pointset # for meshes from stentseg.stentdirect.stentgraph import create_mesh from visvis.processing import lineToMesh, combineMeshes from visvis import ssdf from stentseg.utils.picker import pick3d try: from PyQt4 import QtCore, QtGui # PyQt5 except ImportError: from PySide import QtCore, QtGui # PySide2 from stentseg.apps.ui_dialog import MyDialog from stentseg.utils.centerline import dist_over_centerline # added for Mirthe import copy cropname = 'prox' exceldir = os.path.join(basedir,ptcode) # Load deformations and avg ct (forward for mesh) # centerlines combined in 1 model m = loadmodel(basedir, ptcode, ctcode, cropname, modelname = 'centerline_total_modelavgreg_deforms') model = m.model # centerlines separated in a model for each centerline # m_sep = loadmodel(basedir, ptcode, ctcode, cropname, modelname = 'centerline_modelavgreg_deforms') s = loadvol(basedir, ptcode, ctcode, cropname, what='avgreg') vol_org = copy.deepcopy(s.vol) s.vol.sampling = [vol_org.sampling[1], vol_org.sampling[1], vol_org.sampling[2]] s.sampling = s.vol.sampling vol = s.vol # Start visualization and GUI fig = vv.figure(30); vv.clf() fig.position = 0.00, 30.00, 944.00, 1002.00 a = vv.gca() a.axis.axisColor = 1,1,1 a.axis.visible = True a.bgcolor = 0,0,0 a.daspect = 1, 1, -1 lim = 2500 t = vv.volshow(vol, clim=(0, lim), renderStyle='mip') pick3d(vv.gca(), vol) b = model.Draw(mc='b', mw = 0, lc='g', alpha = 0.5) vv.xlabel('x (mm)');vv.ylabel('y (mm)');vv.zlabel('z (mm)') vv.title('Model for LSPEAS %s - %s' % (ptcode[7:], ctcode)) # Add clickable nodes t0 = time.time() node_points = [] for i, node in enumerate(sorted(model.nodes())): node_point = vv.solidSphere(translation = (node), scaling = (0.6,0.6,0.6)) node_point.faceColor = 'b' node_point.alpha = 0.5 node_point.visible = True node_point.node = node node_point.nr = i node_points.append(node_point) t1 = time.time() print('Clickable nodes created, which took %1.2f min.' % ((t1-t0)/60)) # list of correctly clicked nodes selected_nodes_sum = set() # Initialize labels t0 = vv.Label(a, '\b{Node nr|location}: ', fontSize=11, color='w') t0.position = 0.1, 25, 0.5, 20 # x (frac w), y, w (frac), h t0.bgcolor = None t0.visible = True t1 = vv.Label(a, '\b{Nodepair}: ', fontSize=11, color='w') t1.position = 0.1, 45, 0.5, 20 t1.bgcolor = None t1.visible = True # Initialize output variable to store pulsatility analysis storeOutput = list() def on_key(event): if event.key == vv.KEY_ENTER: # mogenlijkheden aantal nodes # 1 voor relative beweging vanuit avg punt # 2 voor onderlinge beweging tussen twee punten # 3 voor hoek in punt 2 van punt 1 naar punt 3 if len(selected_nodes) == 1: selectn1 = selected_nodes[0].node n1index = selected_nodes[0].nr n1Deforms = model.node[selectn1]['deforms'] output = point_pulsatility(selectn1, n1Deforms) output['NodesIndex'] = [n1index] # Store output with name dialog_output = get_index_name() output['Name'] = dialog_output storeOutput.append(output) # update labels t1.text = '\b{Node}: %i' % (n1index) t1.visible = True print('selection of 1 node stored') if len(selected_nodes) == 2: # get nodes selectn1 = selected_nodes[0].node selectn2 = selected_nodes[1].node # get index of nodes which are in fixed order n1index = selected_nodes[0].nr n2index = selected_nodes[1].nr nindex = [n1index, n2index] # get deforms of nodes n1Deforms = model.node[selectn1]['deforms'] n2Deforms = model.node[selectn2]['deforms'] # get pulsatility cl_merged = append_centerlines(allcenterlines) output = point_to_point_pulsatility(cl_merged, selectn1, n1Deforms, selectn2, n2Deforms, type='euclidian') output['NodesIndex'] = nindex # get distance_centerline #dist_cl = dist_over_centerline(cl_merged, selectn1, selectn2, type='euclidian') # toegevoegd Mirthe #dist_cl = dist_centerline_total(cl_merged, selectn1, # n1Deforms, selectn2, n2Deforms, type='euclidian') # Store output with name dialog_output = get_index_name() output['Name'] = dialog_output storeOutput.append(output) # update labels t1.text = '\b{Node pair}: %i - %i' % (nindex[0], nindex[1]) t1.visible = True print('selection of 2 nodes stored') if len(selected_nodes) == 3: # get nodes selectn1 = selected_nodes[0].node selectn2 = selected_nodes[1].node selectn3 = selected_nodes[2].node # get index of nodes which are in fixed order n1index = selected_nodes[0].nr n2index = selected_nodes[1].nr n3index = selected_nodes[2].nr nindex = [n1index, n2index, n3index] # get deforms of nodes n1Deforms = model.node[selectn1]['deforms'] n2Deforms = model.node[selectn2]['deforms'] n3Deforms = model.node[selectn3]['deforms'] # get angulation output = line_line_angulation(selectn1, n1Deforms, selectn2, n2Deforms, selectn3, n3Deforms) output['NodesIndex'] = nindex # Store output with name dialog_output = get_index_name() output['Name'] = dialog_output storeOutput.append(output) # update labels t1.text = '\b{Nodes}: %i - %i - %i' % (nindex[0], nindex[1], nindex[2]) t1.visible = True print('selection of 3 nodes stored') if len(selected_nodes) > 3: for node in selected_nodes: node.faceColor = 'b' selected_nodes.clear() print('to many nodes selected, select 1,2 or 3 nodes') if len(selected_nodes) < 1: for node in selected_nodes: node.faceColor = 'b' selected_nodes.clear() print('to few nodes selected, select 1,2 or 3 nodes') # Visualize analyzed nodes and deselect for node in selected_nodes: selected_nodes_sum.add(node) for node in selected_nodes_sum: node.faceColor = 'g' # make green when analyzed selected_nodes.clear() if event.key == vv.KEY_ESCAPE: # FINISH MODEL, STORE TO EXCEL # Store to EXCEL storeOutputToExcel(storeOutput, exceldir) vv.close(fig) print('output stored to excel') selected_nodes = list() def select_node(event): """ select and deselect nodes by Double Click """ if event.owner not in selected_nodes: event.owner.faceColor = 'r' selected_nodes.append(event.owner) elif event.owner in selected_nodes: event.owner.faceColor = 'b' selected_nodes.remove(event.owner) def pick_node(event): nodenr = event.owner.nr node = event.owner.node t0.text = '\b{Node nr|location}: %i | x=%1.3f y=%1.3f z=%1.3f' % (nodenr,node[0],node[1],node[2]) def unpick_node(event): t0.text = '\b{Node nr|location}: ' def point_pulsatility(point1, point1Deforms): n1Indices = point1 + point1Deforms pos_combinations = list(itertools.combinations(range(len(point1Deforms)),2)) distances = [] for i in pos_combinations: v = point1Deforms[i[0]] - point1Deforms[i[1]] distances.append(((v[0]**2 + v[1]**2 + v[2]**2)**0.5 )) distances = np.array(distances) # get max distance between phases point_phase_max = distances.max() point_phase_max = [point_phase_max, [x*10 for x in (pos_combinations[list(distances).index(point_phase_max)])]] # get min distance between phases point_phase_min = distances.min() point_phase_min = [point_phase_min, [x*10 for x in (pos_combinations[list(distances).index(point_phase_min)])]] return {'point_phase_min':point_phase_min,'point_phase_max': point_phase_max, 'Node1': [point1, point1Deforms]} def point_to_point_pulsatility(cl, point1, point1Deforms, point2, point2Deforms,type='euclidian'): import numpy as np n1Indices = point1 + point1Deforms n2Indices = point2 + point2Deforms # define vector between nodes v = n1Indices - n2Indices distances = ( (v[:,0]**2 + v[:,1]**2 + v[:,2]**2)**0.5 ).reshape(-1,1) # get min and max distance point_to_pointMax = distances.max() point_to_pointMin = distances.min() # add phase in cardiac cycle where min and max where found (5th = 50%) point_to_pointMax = [point_to_pointMax, (list(distances).index(point_to_pointMax) )*10] point_to_pointMin = [point_to_pointMin, (list(distances).index(point_to_pointMin) )*10] # get median of distances point_to_pointMedian = np.percentile(distances, 50) # Q2 # median of the lower half, Q1 and upper half, Q3 point_to_pointQ1 = np.percentile(distances, 25) point_to_pointQ3 = np.percentile(distances, 75) # Pulsatility min max distance point to point point_to_pointP = point_to_pointMax[0] - point_to_pointMin[0] # add % change to pulsatility point_to_pointP = [point_to_pointP, (point_to_pointP/point_to_pointMin[0])*100 ] # find index of point on cll and calculate length change cll ??? if isinstance(cl, PointSet): cl = np.asarray(cl).reshape((len(cl),3)) indpoint1 = np.where( np.all(cl == point1, axis=-1) )[0] # -1 counts from last to the first axis indpoint2 = np.where( np.all(cl == point2, axis=-1) )[0] # renal point n1Indices = point1 + point1Deforms n2Indices = point2 + point2Deforms clDeforms = [] clpart_deformed = [] vectors = [] clpart = [] d = [] dist_cl = [] clpartDeforms = [] clpart_deformed_test = [] for i in range(len(cl)): clDeforms1 = model.node[cl[i,0], cl[i,1], cl[i,2]]['deforms'] clDeforms.append(clDeforms1) clpart_deformed1 = cl[i] + clDeforms1 clpart_deformed.append(clpart_deformed1) # clpart = cl[min(indpoint1[0], indpoint2[0]):max(indpoint1[0], indpoint2[0])+1] clpart = clpart_deformed[min(indpoint1[0], indpoint2[0]):max(indpoint1[0], indpoint2[0])+1] # for i in range(len(clpart)): # clpartDeforms1 = model.node[clpart[i,0], clpart[i,1], clpart[i,2]]['deforms'] # clpartDeforms.append(clpartDeforms1) # clpart_deformed1_test = cl[i] + clpartDeforms1 # clpart_deformed_test.append(clpart_deformed1_test) # for k in range(len(n1Indices)): # vectors_phases = np.vstack([clpart_deformed_test[i+1][k]-clpart_deformed_test[i][k] for i in range(len(clpart)-1)]) # vectors.append(vectors_phases) for k in range(len(n1Indices)): vectors_phases = np.vstack([clpart[i+1][k]-clpart[i][k] for i in range(len(clpart)-1)]) vectors.append(vectors_phases) for i in range(len(vectors)): if type == 'euclidian': d1 = (vectors[i][:,0]**2 + vectors[i][:,1]**2 + vectors[i][:,2]**2)**0.5 # 3Dvector length in mm d.append(d1) elif type == 'z': d = abs(vectors[i][:,2]) # x,y,z ; 1Dvector length in mm for i in range(len(d)): dist = d[i].sum() dist_cl.append(dist) #if indpoint2 > indpoint1: # stent point proximal to renal on centerline: positive #dist_cl*=-1 cl_min_index1 = np.argmin(dist_cl) cl_min_index = cl_min_index1*10 cl_min = min(dist_cl) cl_max_index1 = np.argmax(dist_cl) cl_max_index = cl_max_index1*10 cl_max = max(dist_cl) print ([dist_cl]) print ([point1, point2]) return {'point_to_pointMin': point_to_pointMin, 'point_to_pointQ1': point_to_pointQ1, 'point_to_pointMedian': point_to_pointMedian, 'point_to_pointQ3': point_to_pointQ3, 'point_to_pointMax': point_to_pointMax, 'point_to_pointP': point_to_pointP, 'Node1': [point1, point1Deforms], 'Node2': [point2, point2Deforms], 'distances': distances, 'dist_cl': dist_cl, 'cl_min_index': cl_min_index, 'cl_max_index': cl_max_index, 'cl_min': cl_min, 'cl_max': cl_max} def line_line_angulation(point1, point1Deforms, point2, point2Deforms, point3, point3Deforms): n1Indices = point1 + point1Deforms n2Indices = point2 + point2Deforms n3Indices = point3 + point3Deforms # get vectors v1 = n1Indices - n2Indices v2 = n3Indices - n2Indices # get angles angles = [] for i in range(len(v1)): angles.append(math.degrees(math.acos((np.dot(v1[i],v2[i]))/ (np.linalg.norm(v1[i])*np.linalg.norm(v2[i]))))) angles = np.array(angles) # get all angle differences of all phases pos_combinations = list(itertools.combinations(range(len(v1)),2)) angle_diff = [] for i in pos_combinations: v = point1Deforms[i[0]] - point1Deforms[i[1]] angle_diff.append(abs(angles[i[0]] - angles[i[1]])) angle_diff = np.array(angle_diff) # get max angle differences point_angle_diff_max = angle_diff.max() point_angle_diff_max = [point_angle_diff_max, [x*10 for x in (pos_combinations[list(angle_diff).index(point_angle_diff_max)])]] # get min angle differences point_angle_diff_min = angle_diff.min() point_angle_diff_min = [point_angle_diff_min, [x*10 for x in (pos_combinations[list(angle_diff).index(point_angle_diff_min)])]] return {'point_angle_diff_min':point_angle_diff_min, 'point_angle_diff_max': point_angle_diff_max, 'angles': angles, 'Node1': [point1, point1Deforms], 'Node2': [point2, point2Deforms], 'Node3': [point3, point1Deforms]} def append_centerlines(allcenterlines): """ Merge seperated PointSet centerlines into one PointSet """ # cl_merged = allcenterlines[0] cl_merged = PointSet(3) for i in range(0,len(allcenterlines)): for point in allcenterlines[i]: cl_merged.append(point) return cl_merged def get_index_name(): # Gui for input name app = QtGui.QApplication([]) m = MyDialog() m.show() m.exec_() dialog_output = m.edit.text() return dialog_output def storeOutputToExcel(storeOutput, exceldir): """Create file and add a worksheet or overwrite existing """ # https://pypi.python.org/pypi/XlsxWriter workbook = xlsxwriter.Workbook(os.path.join(exceldir,'storeOutput.xlsx')) worksheet = workbook.add_worksheet('General') # set column width worksheet.set_column('A:A', 35) worksheet.set_column('B:B', 30) # add a bold format to highlight cells bold = workbook.add_format({'bold': True}) # write title and general tab worksheet.write('A1', 'Output ChEVAS dynamic CT, 10 Phases', bold) analysisID = '%s_%s_%s' % (ptcode, ctcode, cropname) worksheet.write('A2', 'Filename:', bold) worksheet.write('B2', analysisID) worksheet.write('A3', 'Date and Time:', bold) date_time = datetime.now() #strftime("%d-%m-%Y %H:%M") date_format_str = 'dd-mm-yyyy hh:mm' date_format = workbook.add_format({'num_format': date_format_str, 'align': 'left'}) worksheet.write_datetime('B3', date_time, date_format) # write 'storeOutput' sort_index = [] for i in range(len(storeOutput)): type = len(storeOutput[i]['NodesIndex']) sort_index.append([i, type]) sort_index = np.array(sort_index) sort_index = sort_index[sort_index[:,1].argsort()] for i, n in sort_index: worksheet = workbook.add_worksheet(storeOutput[i]['Name']) worksheet.set_column('A:A', 35) worksheet.set_column('B:B', 20) worksheet.write('A1', 'Name:', bold) worksheet.write('B1', storeOutput[i]['Name']) if n == 1: worksheet.write('A2', 'Type:', bold) worksheet.write('B2', '1 Node') worksheet.write('A3', 'Minimum translation (mm, Phases)',bold) worksheet.write('B3', storeOutput[i]['point_phase_min'][0]) worksheet.write_row('C3', list(storeOutput[i]['point_phase_min'][1])) worksheet.write('A4', 'Maximum translation (mm, Phases)',bold) worksheet.write('B4', storeOutput[i]['point_phase_max'][0]) worksheet.write_row('C4', list(storeOutput[i]['point_phase_max'][1])) worksheet.write('A5', 'Avg node position and deformations', bold) worksheet.write('B5', str(list(storeOutput[i]['Node1'][0]))) worksheet.write_row('C5', [str(x)for x in list(storeOutput[i]['Node1'][1])]) worksheet.write('A6', 'Node Index Number', bold) worksheet.write_row('B6', list(storeOutput[i]['NodesIndex'])) elif n == 2: worksheet.write('A2', 'Type:', bold) worksheet.write('B2', '2 Nodes') worksheet.write('A3', 'Minimum distance (mm, Phases)',bold) worksheet.write('B3', storeOutput[i]['point_to_pointMin'][0]) worksheet.write('C3', storeOutput[i]['point_to_pointMin'][1]) worksheet.write('A4', 'Q1 distance (mm)',bold) worksheet.write('B4', storeOutput[i]['point_to_pointQ1']) worksheet.write('A5', 'Median distance (mm)',bold) worksheet.write('B5', storeOutput[i]['point_to_pointMedian']) worksheet.write('A6', 'Q3 distance (mm)',bold) worksheet.write('B6', storeOutput[i]['point_to_pointQ3']) worksheet.write('A7', 'Maximum distance (mm, phases)',bold) worksheet.write('B7', storeOutput[i]['point_to_pointMax'][0]) worksheet.write('C7', storeOutput[i]['point_to_pointMax'][1]) worksheet.write('A8', 'Maximum distance difference (mm)', bold) worksheet.write('B8', storeOutput[i]['point_to_pointP'][0]) worksheet.write('A9', 'Distances for each phase', bold) worksheet.write_row('B9', [str(x) for x in list(storeOutput[i]['distances'])]) worksheet.write('A10', 'Avg node1 position and deformations', bold) worksheet.write('B10', str(list(storeOutput[i]['Node1'][0]))) worksheet.write_row('C10', [str(x) for x in list(storeOutput[i]['Node1'][1])]) worksheet.write('A11', 'Avg node2 position and deformations', bold) worksheet.write('B11', str(list(storeOutput[i]['Node2'][0]))) worksheet.write_row('C11', [str(x) for x in list(storeOutput[i]['Node2'][1])]) worksheet.write('A12', 'Node Index Number', bold) worksheet.write_row('B12', list(storeOutput[i]['NodesIndex'])) worksheet.write('A13', 'Length centerline', bold) worksheet.write('B13', str(list(storeOutput[i]['dist_cl']))) worksheet.write('A14', 'Minimum length centerline', bold) worksheet.write('B14', storeOutput[i]['cl_min']) worksheet.write('C14', storeOutput[i]['cl_min_index']) worksheet.write('A15', 'Maximum length centerline', bold) worksheet.write('B15', storeOutput[i]['cl_max']) worksheet.write('C15', storeOutput[i]['cl_max_index']) elif n == 3: worksheet.write('A2', 'Type:', bold) worksheet.write('B2', '3 Nodes') worksheet.write('A3', 'Minimum angle difference (degrees, Phases)',bold) worksheet.write('B3', storeOutput[i]['point_angle_diff_min'][0]) worksheet.write_row('C3', list(storeOutput[i]['point_angle_diff_min'][1])) worksheet.write('A4', 'Maximum angle difference (degrees, Phases)',bold) worksheet.write('B4', storeOutput[i]['point_angle_diff_max'][0]) worksheet.write_row('C4', list(storeOutput[i]['point_angle_diff_max'][1])) worksheet.write('A5', 'Angles for each phase (degrees)',bold) worksheet.write_row('B5', list(storeOutput[i]['angles'])) worksheet.write('A6', 'Avg node1 position and deformations', bold) worksheet.write('B6', str(list(storeOutput[i]['Node1'][0]))) worksheet.write_row('C6', [str(x) for x in list(storeOutput[i]['Node1'][1])]) worksheet.write('A7', 'Avg node2 position and deformations', bold) worksheet.write('B7', str(list(storeOutput[i]['Node2'][0]))) worksheet.write_row('C7', [str(x) for x in list(storeOutput[i]['Node2'][1])]) worksheet.write('A8', 'Avg node2 position and deformations', bold) worksheet.write('B8', str(list(storeOutput[i]['Node3'][0]))) worksheet.write_row('C8', [str(x) for x in list(storeOutput[i]['Node3'][1])]) worksheet.write('A9', 'Node Index Number', bold) worksheet.write_row('B9', list(storeOutput[i]['NodesIndex'])) workbook.close() # Bind event handlers fig.eventKeyDown.Bind(on_key) for node_point in node_points: node_point.eventDoubleClick.Bind(select_node) node_point.eventEnter.Bind(pick_node) node_point.eventLeave.Bind(unpick_node)