def DrawModelAxes(vol, graph=None, ax=None, axVis=False, meshColor=None, getLabel=False, mc='b', lc='g', mw=7, lw=0.6, **kwargs): """ Draw model with volume with axes set ax = axes to draw (a1 or a2 or a3); graph = sd._nodes1 or 2 or 3 meshColor = None or faceColor e.g. 'g' """ #todo: prevent TypeError: draw() got an unexpected keyword argument mc/lc when not given as required variable #todo: *args voor vol in drawModelAxes of **kwargs[key] in functies hieronder if ax is None: ax = vv.gca() ax.MakeCurrent() ax.daspect = 1, 1, -1 ax.axis.axisColor = 1, 1, 1 ax.bgcolor = 0, 0, 0 ax.axis.visible = axVis vv.xlabel('x (mm)') vv.ylabel('y (mm)') vv.zlabel('z (mm)') if graph is None: show_ctvolume(vol, graph, axis=ax, removeStent=False, **kwargs) label = pick3d(vv.gca(), vol) return label if hasattr(graph, 'number_of_edges'): if graph.number_of_edges( ) == 0: # get label from picked seeds sd._nodes1 show_ctvolume(vol, graph, axis=ax, **kwargs) label = pick3d(vv.gca(), vol) graph.Draw(mc=mc, lc=lc) return label if not meshColor is None: bm = create_mesh(graph, 0.5) # (argument is strut tickness) m = vv.mesh(bm) m.faceColor = meshColor # 'g' show_ctvolume(vol, graph, axis=ax, **kwargs) graph.Draw(mc=mc, lc=lc) if getLabel == True: label = pick3d(vv.gca(), vol) return label else: pick3d(vv.gca(), vol) return
def nodeInteraction(model, vol, selected_nodes): """ modify edges in dynamic model and make dynamic again """ f = vv.figure() vv.clf() f.position = 8.00, 30.00, 944.00, 1002.00 a = vv.gca() a.axis.axisColor = 1, 1, 1 a.axis.visible = False a.bgcolor = 0, 0, 0 a.daspect = 1, 1, -1 lim = (0, 2500) t = vv.volshow(vol, clim=lim, renderStyle='mip') pick3d(vv.gca(), vol) model.Draw(mc='b', mw=10, lc='g') vv.xlabel('x (mm)') vv.ylabel('y (mm)') vv.zlabel('z (mm)') vv.title('User interaction to modify model %s - %s' % (ptcode[-3:], ctcode)) t3 = vv.Label(a, 'Edge length: ', fontSize=11, color='c') t3.position = 0.1, 55, 0.5, 20 t3.bgcolor = None t3.visible = False # create clickable nodes node_points = _utils_GUI.interactive_node_points(model, scale=0.6) # bind event handlers f.eventKeyDown.Bind(lambda event: _utils_GUI.ViewPresets(event, [a])) f.eventKeyDown.Bind(on_key) for node_point in node_points: node_point.eventDoubleClick.Bind( lambda event: _utils_GUI.select_node(event, selected_nodes)) print('') print('UP/DOWN = show/hide nodes') print('DELETE = remove edge [select 2 nodes] or pop node [select 1 node]') print('s = additional smooth') print('e = smooth selected edge') print('w = clear selected nodes') print('q = activate "interactiveClusterRemoval"') print('ALT = pop nodes') print('ESCAPE = make model dynamic and save to disk') print('') return node_points, t3
def show_surface_and_vol(vol, pp_isosurface, showVol='MIP', clim=(-200, 1000), isoTh=300, climEditor=True): """ Show the generated isosurface in original volume """ f = vv.figure() ax = vv.gca() ax.daspect = 1, 1, -1 ax.axis.axisColor = 1, 1, 1 ax.bgcolor = 0, 0, 0 # show vol and iso vertices show_ctvolume(vol, showVol=showVol, isoTh=isoTh, clim=clim, climEditor=climEditor) label = pick3d(vv.gca(), vol) vv.plot(pp_isosurface, ms='.', ls='', mc='r', alpha=0.2, mw=4) a = vv.gca() f.eventKeyDown.Bind(lambda event: _utils_GUI.ViewPresets(event, [a])) print('------------------------') print('Use keys 1, 2, 3, 4 and 5 for preset anatomic views') print('Use v for a default zoomed view') print('Use x to show and hide axis') print('------------------------') vv.xlabel('x (mm)') vv.ylabel('y (mm)') vv.zlabel('z (mm)') return label
def showModel3d(basedir,ptcode, ctcode, cropname='ring', showVol='MIP', showmodel=True, graphname='model', **kwargs): """ show model and vol in 3d by mip iso or 2D graphname 'all' draws all graph models stored in s, if multiple """ s = loadmodel(basedir, ptcode, ctcode, cropname, modelname='modelavgreg') vol = loadvol(basedir, ptcode, ctcode, cropname, what='avgreg').vol # figure f = vv.figure(); vv.clf() f.position = 0.00, 22.00, 1920.00, 1018.00 a = vv.gca() a.axis.axisColor = 1,1,1 a.axis.visible = False a.bgcolor = 0,0,0 a.daspect = 1, 1, -1 t = show_ctvolume(vol, axis=a, showVol=showVol, removeStent=False, climEditor=True, **kwargs) label = pick3d(a, vol) vv.xlabel('x (mm)');vv.ylabel('y (mm)');vv.zlabel('z (mm)') if showmodel: if graphname == 'all': for key in dir(s): if key.startswith('model'): s[key].Draw(mc='b', mw = 5, lc='g', alpha = 0.5) else: s[graphname].Draw(mc='b', mw = 5, lc='g', alpha = 0.5) vv.title('Model for LSPEAS %s - %s' % (ptcode[8:], ctcode)) # f.eventKeyDown.Bind(lambda event: _utils_GUI.RotateView(event, [a], axishandling=False )) f.eventKeyDown.Bind(lambda event: _utils_GUI.ViewPresets(event, [a]) ) return f, a, label, s
def drawmodelphasescycles(vol1, model1, modelori1, showVol, isoTh=300, removeStent=False, showmodelavgreg=False, showvol=True, phases=range(10), colors='cgmrcgywmb', meshWithColors=False, stripSizeZ=None, ax=None): """ draw model and volume (show optional) at different phases cycle """ if ax is None: ax = vv.gca() ax.daspect = 1, 1, -1 ax.axis.axisColor = 0, 0, 0 ax.bgcolor = 1, 1, 1 vv.xlabel('x (mm)') vv.ylabel('y (mm)') vv.zlabel('z (mm)') # draw t = show_ctvolume(vol1, modelori1, showVol=showVol, removeStent=removeStent, climEditor=True, isoTh=isoTh, clim=clim0, stripSizeZ=stripSizeZ) if showmodelavgreg: # show model and CT mid cycle mw = 5 for model in model1: model.Draw(mc='b', mw=mw, lc='b', alpha=0.5) label = pick3d(ax, vol1) if not showvol: t.visible = False # get models in different phases for model in model1: for phasenr in phases: model_phase = get_graph_in_phase(model, phasenr=phasenr) if meshWithColors: modelmesh1 = create_mesh_with_abs_displacement(model_phase, radius=radius, dim=dimensions) m = vv.mesh(modelmesh1, colormap=vv.CM_JET, clim=clim2) #todo: use colormap Viridis or Magma as JET is not linear (https://bids.github.io/colormap/) else: model_phase.Draw(mc=colors[phasenr], mw=10, lc=colors[phasenr]) # modelmesh1 = create_mesh(model_phase, radius = radius) # m = vv.mesh(modelmesh1); m.faceColor = colors[phasenr] if meshWithColors: vv.colorbar() return ax
def remove_nodes_by_selected_point(graph, vol, axes, label, clim, location='posterior', **kwargs): """ removes nodes and edges in graph. Graph is separated by coord of selected point use location to define what to remove, e.g. posterior to remove nodes in spine Input : graph, axes, label of selected point, dimension how to separate graph Output: graph is modified locally and visualized in current view """ from stentseg.utils.picker import pick3d, label2worldcoordinates from stentseg.utils.visualization import DrawModelAxes if graph is None: print('No nodes removed, graph is NoneType') return coord1 = np.asarray(label2worldcoordinates(label), dtype=np.float32) # x,y,z if location == 'posterior': seeds = np.asarray(sorted( graph.nodes(), key=lambda x: x[1])) # sort dim small to large falseindices = np.where( seeds[:, 1] > coord1[1] ) # tuple wih array of indices with values higher than coord y = 1 if location == 'anterior': seeds = np.asarray(sorted(graph.nodes(), key=lambda x: x[1])) falseindices = np.where(seeds[:, 1] < coord1[1]) elif location == 'proximal': seeds = np.asarray(sorted(graph.nodes(), key=lambda x: x[2])) falseindices = np.where( seeds[:, 2] < coord1[2]) # dim z = 2; origin proximal elif location == 'distal': seeds = np.asarray(sorted(graph.nodes(), key=lambda x: x[2])) falseindices = np.where(seeds[:, 2] > coord1[2]) # dim z = 2 elif location == 'left': seeds = np.asarray(sorted(graph.nodes(), key=lambda x: x[0])) falseindices = np.where(seeds[:, 0] > coord1[0]) elif location == 'right': seeds = np.asarray(sorted(graph.nodes(), key=lambda x: x[0])) falseindices = np.where(seeds[:, 0] < coord1[0]) # get seeds for removal by indices falseseeds = seeds[falseindices[0]] # remove from graph graph.remove_nodes_from(tuple(map( tuple, falseseeds))) # use map to convert to tuples view = axes.GetView() axes.Clear() DrawModelAxes(vol, graph, ax=axes, clim=clim, **kwargs) axes.SetView(view) if graph.number_of_edges() == 0: # get label from picked seeds sd._nodes1 label = pick3d(vv.gca(), vol) return label
def reDrawModel(vol, model, ax=None, selected_nodes=[]): if ax is None: ax = vv.gca() view = ax.GetView() ax.Clear() lim = (0, 2500) t = vv.volshow(vol, clim=lim, renderStyle='mip') pick3d(vv.gca(), vol) model.Draw(mc='g', mw=10, lc='g') node_points = _utils_GUI.interactive_node_points(model, scale=0.6) _utils_GUI.node_points_callbacks(node_points, selected_nodes, pick=False) # see if node_points are still selected to color them red for node_point in node_points: node_point.visible = True for i, node in enumerate(selected_nodes): if node_point.node == node.node: selected_nodes[i] = node_point node_point.faceColor = (1, 0, 0) ax.SetView(view) return node_points
## Load all rings of the limb for i in nrs: ring = 'ringR%s' %(i) filename = '%s_%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname, 'model'+what,ring) s["ringR" + str(i)] = ssdf.load(os.path.join(basedir1, filename)) ## Visualize centerlines rings s2 = loadmodel(targetdir2, ptcode, ctcode, cropname, modelname='stentseedsavgreg') pmodel = points_from_nodes_in_graph(s2.model) if FIG1 == True: f = vv.figure(1); vv.clf() f.position = 709.00, 30.00, 1203.00, 1008.00 a1 = vv.subplot(121) show_ctvolume(s.vol, None, showVol=showVol, clim=clim0, isoTh=isoTh, removeStent=False) label = pick3d(vv.gca(), s.vol) a1.axis.visible = showAxis a1.daspect = 1,1,-1 a2 = vv.subplot(122) vv.plot(pmodel, ms='.', ls='', alpha=0.2, mw = 2) # stent seed points for i in nrs: pp = s["ringR" + str(i)].ringpoints vv.plot(pp[0],pp[1],pp[2], ms='.', ls='', mw=3, mc='c') a2.axis.visible = showAxis a2.daspect = 1,1,-1 # a1.camera = a2.camera ## Distances # Obtain minimal distances from all points on ring to a point on ring below
fig = vv.figure() vv.clf() fig.position = 0.00, 22.00, 1920.00, 1018.00 clim = (0, 2500) # Show volume a1 = vv.subplot(111) a1.daspect = 1, 1, -1 t = show_ctvolume(vol, axis=a1, showVol='ISO', clim=clim, isoTh=250, removeStent=False, climEditor=True) label = pick3d(vv.gca(), vol) vv.xlabel('x (mm)') vv.ylabel('y (mm)') vv.zlabel('z (mm)') ## Show 3D movie, by alternating the 10 volumes # Load volumes s = loadvol(basedir, ptcode, ctcode, cropname, 'phases') vols = [] for key in dir(s): if key.startswith('vol'): zscale = (s[key].sampling[0] / s[key].sampling[1]) # z / y # resample vol using spline interpolation, 3rd order polynomial vol_zoom = scipy.ndimage.interpolation.zoom(s[key], [zscale, 1, 1], 'float32')
def identify_peaks_valleys(midpoints_peaks_valleys, model, vol, vis=True): """ Given a cloud of points containing 2 peak and 2 valley points for R1 and R2, identify and return these locations. Uses clustering and x,y,z """ # detect clusters to further label locations kmeans = KMeans(n_clusters=4) kmeans.fit(midpoints_peaks_valleys) centroids = kmeans.cluster_centers_ # x,y,z labels = kmeans.labels_ # identify left, right, ant, post centroid (assumes origin is prox right anterior) left = list(centroids[:, 0]).index(max(centroids[:, 0])) # max x value right = list(centroids[:, 0]).index(min(centroids[:, 0])) anterior = list(centroids[:, 1]).index(min(centroids[:, 1])) # min y value posterior = list(centroids[:, 1]).index(max(centroids[:, 1])) # get points into grouped arrays cLeft, cRight, cAnterior, cPosterior = [], [], [], [] for i, p in enumerate(midpoints_peaks_valleys): if labels[i] == left: cLeft.append(tuple(p.flat)) elif labels[i] == right: cRight.append(tuple(p.flat)) elif labels[i] == anterior: cAnterior.append(tuple(p.flat)) elif labels[i] == posterior: cPosterior.append(tuple(p.flat)) cLeft = np.asarray(cLeft) cRight = np.asarray(cRight) cAnterior = np.asarray(cAnterior) cPosterior = np.asarray(cPosterior) # divide into R1 R2 R1_left = cLeft[list(cLeft[:, 2]).index(min( cLeft[:, 2]))] # min z for R1; valley R2_left = cLeft[list(cLeft[:, 2]).index(max(cLeft[:, 2]))] # valley R1_right = cRight[list(cRight[:, 2]).index(min( cRight[:, 2]))] # min z for R1; valley R2_right = cRight[list(cRight[:, 2]).index(max(cRight[:, 2]))] # valley R1_ant = cAnterior[list(cAnterior[:, 2]).index(min( cAnterior[:, 2]))] # min z for R1; peak R2_ant = cAnterior[list(cAnterior[:, 2]).index(max(cAnterior[:, 2]))] # peak R1_post = cPosterior[list(cPosterior[:, 2]).index(min( cPosterior[:, 2]))] # min z for R1; peak R2_post = cPosterior[list(cPosterior[:, 2]).index(max(cPosterior[:, 2]))] # peak if vis == True: # visualize identified locations f = vv.figure(1) vv.clf() f.position = 968.00, 30.00, 944.00, 1002.00 a = vv.gca() colors = ['r', 'g', 'b', 'm', 'c', 'y', 'w', 'k'] for i, p in enumerate([ R1_left, R2_left, R1_right, R2_right, R1_ant, R2_ant, R1_post, R2_post ]): vv.plot(p[0], p[1], p[2], ms='.', ls='', mc=colors[i], mw=14) vv.legend('R1 left', 'R2 left', 'R1 right', 'R2 right', 'R1 ant', 'R2 ant', 'R1 post', 'R2 post') show_ctvolume(vol, model, showVol='MIP', clim=(0, 2500)) pick3d(vv.gca(), vol) model.Draw(mc='b', mw=10, lc='g') for i in range(len(midpoints_peaks_valleys)): vv.plot(midpoints_peaks_valleys[i], ms='.', ls='', mc=colors[labels[i]], mw=6) a.axis.axisColor = 1, 1, 1 a.bgcolor = 0, 0, 0 a.daspect = 1, 1, -1 # z-axis flipped a.axis.visible = True return R1_left, R2_left, R1_right, R2_right, R1_ant, R2_ant, R1_post, R2_post
def identifyCenterlines(s, ptcode, ctcode, basedir, modelname, showVol='MIP', **kwargs): """ s is struct with models """ from stentseg.utils.datahandling import select_dir, loadvol, loadmodel from stentseg.utils.picker import pick3d from stentseg.utils.visualization import show_ctvolume from stentseg.utils import _utils_GUI showAxis = False # showVol = 'MIP' # MIP or ISO or 2D or None clim = (0, 2500) # clim = -200,500 # 2D isoTh = 250 cropname = 'prox' # init fig f = vv.figure() vv.clf() f.position = 0.00, 22.00, 1920.00, 1018.00 # load vol svol = loadvol(basedir, ptcode, ctcode, cropname, what='avgreg') # set sampling for cases where this was not stored correctly svol.vol.sampling = [svol.sampling[1], svol.sampling[1], svol.sampling[2]] vol = svol.vol s.sampling = [svol.sampling[1], svol.sampling[1], svol.sampling[2]] # for model # show vol t = show_ctvolume(vol, showVol=showVol, clim=clim, isoTh=isoTh, **kwargs) label = pick3d(vv.gca(), vol) vv.xlabel('x (mm)') vv.ylabel('y (mm)') vv.zlabel('z (mm)') if showVol == 'MIP': c = vv.ClimEditor(vv.gca()) c.position = (10, 50) f.eventKeyDown.Bind(lambda event: _utils_GUI.ShowHideSlider(event, c)) print('Use "s" to show/hide slider') if showVol == 'ISO': c = _utils_GUI.IsoThEditor(vv.gca()) c.position = (10, 50) f.eventKeyDown.Bind(lambda event: _utils_GUI.ShowHideSlider(event, c)) print('Use "s" to show/hide slider') f.eventKeyDown.Bind( lambda event: _utils_GUI.ViewPresets(event, [vv.gca()])) print('------------------------') print('Use keys 1, 2, 3, 4 and 5 for preset anatomic views') print('Use v for a default zoomed view') print('Use x to show and hide axis') print('------------------------') ax, s2 = interactiveCenterlineID(s, ptcode, ctcode, basedir, cropname, modelname) return ax, s2
ax.axis.axisColor = 0, 0, 0 ax.bgcolor = 1, 1, 1 vv.xlabel('x (mm)') vv.ylabel('y (mm)') vv.zlabel('z (mm)') # draw showVol = 'ISO' t = show_ctvolume(vol, showVol=showVol, removeStent=False, climEditor=True, isoTh=300) if showmodelavgreg: # show model and CT mid cycle mw = 5 modelcll.Draw(mc='b', mw=mw, lc='b', alpha=0.5) label = pick3d(ax, vol) if not showvol: t.visible = False # get centerline models in different phases for phasenr in phases: model_phase = get_graph_in_phase(modelcll, phasenr=phasenr) model_phase.Draw(mc=color[phasenr], mw=10, lc=color[phasenr]) #bind view control f.eventKeyDown.Bind( lambda event: _utils_GUI.RotateView(event, [ax], axishandling=False)) f.eventKeyDown.Bind(lambda event: _utils_GUI.ViewPresets(event, [ax]))
def showModelsStatic(ptcode,codes, vols, ss, mm, vs, showVol, clim, isoTh, clim2, clim2D, drawMesh=True, meshDisplacement=True, drawModelLines=True, showvol2D=False, showAxis=False, drawVessel=False, vesselType=1, meshColor=None, **kwargs): """ show one to four models in multipanel figure. Input: arrays of codes, vols, ssdfs; params from show_models_static Output: axes, colorbars """ # init fig f = vv.figure(1); vv.clf() # f.position = 0.00, 22.00, 1920.00, 1018.00 mw = 5 if drawMesh == True: lc = 'w' meshColor = meshColor else: lc = 'g' # create subplots if isinstance(codes, str): # if 1 ctcode, otherwise tuple of strings a1 = vv.subplot(111) axes = [a1] elif codes == (codes[0],codes[1]): a1 = vv.subplot(121) a2 = vv.subplot(122) axes = [a1,a2] elif codes == (codes[0],codes[1], codes[2]): a1 = vv.subplot(131) a2 = vv.subplot(132) a3 = vv.subplot(133) axes = [a1,a2,a3] elif codes == (codes[0],codes[1], codes[2], codes[3]): a1 = vv.subplot(141) a2 = vv.subplot(142) a3 = vv.subplot(143) a4 = vv.subplot(144) axes = [a1,a2,a3,a4] elif codes == (codes[0],codes[1], codes[2], codes[3], codes[4]): a1 = vv.subplot(151) a2 = vv.subplot(152) a3 = vv.subplot(153) a4 = vv.subplot(154) a5 = vv.subplot(155) axes = [a1,a2,a3,a4,a5] else: a1 = vv.subplot(111) axes = [a1] for i, ax in enumerate(axes): ax.MakeCurrent() vv.xlabel('x (mm)');vv.ylabel('y (mm)');vv.zlabel('z (mm)') vv.title('Model for LSPEAS %s - %s' % (ptcode[7:], codes[i])) t = show_ctvolume(vols[i], ss[i].model, axis=ax, showVol=showVol, clim=clim, isoTh=isoTh, **kwargs) label = pick3d(ax, vols[i]) if drawModelLines == True: ss[i].model.Draw(mc='b', mw = mw, lc=lc) if showvol2D: for i, ax in enumerate(axes): t2 = vv.volshow2(vols[i], clim=clim2D, axes=ax) cbars = [] # colorbars if drawMesh: for i, ax in enumerate(axes): m = vv.mesh(mm[i], axes=ax) if meshDisplacement: m.clim = clim2 m.colormap = vv.CM_JET #todo: use colormap Viridis or Magma as JET is not linear (https://bids.github.io/colormap/) cb = vv.colorbar(ax) cbars.append(cb) elif meshColor is not None: if len(meshColor) == 1: m.faceColor = meshColor[0] # (0,1,0,1) else: m.faceColor = meshColor[i] else: m.faceColor = 'g' if drawVessel: for i, ax in enumerate(axes): v = showVesselMesh(vs[i], ax, type=vesselType) for ax in axes: ax.axis.axisColor = 1,1,1 ax.bgcolor = 25/255,25/255,112/255 # midnightblue # http://cloford.com/resources/colours/500col.htm ax.daspect = 1, 1, -1 # z-axis flipped ax.axis.visible = showAxis # set colorbar position for cbar in cbars: p1 = cbar.position cbar.position = (p1[0], 20, p1[2], 0.98) # x,y,w,h # bind rotate view and view presets [1,2,3,4,5] f = vv.gcf() f.eventKeyDown.Bind(lambda event: _utils_GUI.RotateView(event,axes,axishandling=False) ) f.eventKeyDown.Bind(lambda event: _utils_GUI.ViewPresets(event,axes) ) return axes, cbars
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)
def __init__(self,ptcode,ctcode,basedir, seed_th=[600], show=True, normalize=False, modelname='model'): import os import numpy as np import visvis as vv from visvis import ssdf from stentseg.utils import PointSet, _utils_GUI from stentseg.utils.datahandling import select_dir, loadvol, loadmodel from stentseg.stentdirect.stentgraph import create_mesh from stentseg.stentdirect import stentgraph, StentDirect, getDefaultParams from stentseg.stentdirect import AnacondaDirect, EndurantDirect, NellixDirect from stentseg.utils.visualization import show_ctvolume from stentseg.utils.picker import pick3d, label2worldcoordinates, label2volindices import scipy from scipy import ndimage import copy # Select dataset to register cropname = 'prox' # phase = 10 #dataset = 'avgreg' #what = str(phase) + dataset # avgreg what = 'avgreg' # Load volumes s = loadvol(basedir, ptcode, ctcode, cropname, what) # sampling was not properly stored after registration for all cases: reset sampling vol_org = copy.deepcopy(s.vol) s.vol.sampling = [vol_org.sampling[1], vol_org.sampling[1], vol_org.sampling[2]] # z,y,x s.sampling = s.vol.sampling vol = s.vol ## Initialize segmentation parameters stentType = 'nellix' # 'zenith';'nellix' runs modified pruning algorithm in Step3 p = getDefaultParams(stentType) p.seed_threshold = seed_th # step 1 [lower th] or [lower th, higher th] # p.seedSampleRate = 7 # step 1, nellix p.whatphase = what ## Perform segmentation # Instantiate stentdirect segmenter object if stentType == 'anacondaRing': sd = AnacondaDirect(vol, p) # inherit _Step3_iter from AnacondaDirect class #runtime warning using anacondadirect due to mesh creation, ignore elif stentType == 'endurant': sd = EndurantDirect(vol, p) elif stentType == 'nellix': sd = NellixDirect(vol, p) else: sd = StentDirect(vol, p) ## show histogram and normalize # f = vv.figure(3) # a = vv.gca() # vv.hist(vol, drange=(300,vol.max())) # normalize vol to certain limit if normalize: sd.Step0(3071) vol = sd._vol # b= vv.hist(vol, drange=(300,3071)) # b.color = (1,0,0) ## Perform step 1 for seeds sd.Step1() ## Visualize if show: fig = vv.figure(2); vv.clf() fig.position = 0.00, 22.00, 1920.00, 1018.00 clim = (0,2000) # Show volume and model as graph a1 = vv.subplot(121) a1.daspect = 1,1,-1 # t = vv.volshow(vol, clim=clim) t = show_ctvolume(vol, axis=a1, showVol='MIP', clim =clim, isoTh=250, removeStent=False, climEditor=True) label = pick3d(vv.gca(), vol) sd._nodes1.Draw(mc='b', mw = 2) # draw seeded nodes #sd._nodes2.Draw(mc='b', lc = 'g') # draw seeded and MCP connected nodes vv.xlabel('x (mm)');vv.ylabel('y (mm)');vv.zlabel('z (mm)') # Show volume and cleaned up graph a2 = vv.subplot(122) a2.daspect = 1,1,-1 sd._nodes1.Draw(mc='b', mw = 2) # draw seeded nodes # t = vv.volshow(vol, clim=clim) # label = pick3d(vv.gca(), vol) # sd._nodes2.Draw(mc='b', lc='g') # sd._nodes3.Draw(mc='b', lc='g') vv.xlabel('x (mm)');vv.ylabel('y (mm)');vv.zlabel('z (mm)') # # Show the mesh #=============================================================================== # a3 = vv.subplot(133) # a3.daspect = 1,1,-1 # t = vv.volshow(vol, clim=clim) # pick3d(vv.gca(), vol) # #sd._nodes3.Draw(mc='b', lc='g') # m = vv.mesh(bm) # m.faceColor = 'g' # # _utils_GUI.vis_spared_edges(sd._nodes3) # vv.xlabel('x (mm)');vv.ylabel('y (mm)');vv.zlabel('z (mm)') #=============================================================================== # Use same camera a1.camera = a2.camera #= a3.camera switch = True a1.axis.visible = switch a2.axis.visible = switch #a3.axis.visible = switch ## Store segmentation to disk # Get graph model model = sd._nodes1 # Build struct s2 = vv.ssdf.new() s2.sampling = s.sampling s2.origin = s.origin s2.stenttype = s.stenttype s2.croprange = s.croprange for key in dir(s): if key.startswith('meta'): suffix = key[4:] s2['meta'+suffix] = s['meta'+suffix] s2.what = what s2.params = p s2.stentType = stentType # Store model (not also volume) s2.model = model.pack() # Save filename = '%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname, modelname+ what) ssdf.save(os.path.join(basedir, ptcode, filename), s2) print('saved to disk as {}.'.format(filename) ) ## Make model dynamic (and store/overwrite to disk) #=============================================================================== # # import pirt # from stentsegf.motion.dynamic import incorporate_motion_nodes, incorporate_motion_edges # # # Load deforms # s = loadvol(basedir, ptcode, ctcode, cropname, '10deforms') # deformkeys = [] # for key in dir(s): # if key.startswith('deform'): # deformkeys.append(key) # deforms = [s[key] for key in deformkeys] # deforms = [pirt.DeformationFieldBackward(*fields) for fields in deforms] # paramsreg = s.params # # # Load model # s = loadmodel(basedir, ptcode, ctcode, cropname, 'model'+what) # model = s.model # # # Combine ... # incorporate_motion_nodes(model, deforms, s.origin) # incorporate_motion_edges(model, deforms, s.origin) # # # Save back # filename = '%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname, 'model'+what) # s.model = model.pack() # s.paramsreg = paramsreg # ssdf.save(os.path.join(basedir, ptcode, filename), s) # print('saved to disk as {}.'.format(filename) ) #===============================================================================
def __init__(self, ptcode, ctcode, StartPoints, EndPoints, basedir, modelname='modelavgreg'): """ with start and endpoints provided, calculate centerline and save as ssdf in basedir as model and dynamic model """ #todo: name of dynamic model is now deforms, unclear, should be dynamic #import numpy as np import visvis as vv import numpy as np import os import copy from stentseg.utils import PointSet, _utils_GUI from stentseg.utils.centerline import (find_centerline, points_from_nodes_in_graph, points_from_mesh, smooth_centerline) from stentseg.utils.datahandling import loadmodel, loadvol from stentseg.utils.visualization import show_ctvolume from stentseg.utils.picker import pick3d stentnr = len(StartPoints) cropname = 'prox' what = modelname what_vol = 'avgreg' vismids = True m = loadmodel(basedir, ptcode, ctcode, cropname, what) s = loadvol(basedir, ptcode, ctcode, cropname, what_vol) s.vol.sampling = [s.sampling[1], s.sampling[1], s.sampling[2]] s.sampling = s.vol.sampling start1 = StartPoints.copy() ends = EndPoints.copy() from stentseg.stentdirect import stentgraph ppp = points_from_nodes_in_graph(m.model) allcenterlines = [] # for pp allcenterlines_nosmooth = [] # for pp centerlines = [] # for stentgraph nodes_total = stentgraph.StentGraph() for j in range(stentnr): if j == 0 or not start1[j] == ends[j - 1]: # if first stent or when stent did not continue with this start point nodes = stentgraph.StentGraph() centerline = PointSet(3) # empty # Find main centerline # if j > 3: # for stent with midpoints # centerline1 = find_centerline(ppp, start1[j], ends[j], step= 1, # ndist=10, regfactor=0.5, regsteps=10, verbose=False) #else: centerline1 = find_centerline(ppp, start1[j], ends[j], step=1, ndist=10, regfactor=0.5, regsteps=1, verbose=False) # centerline1 is a PointSet print('Centerline calculation completed') # ========= Maaike ======= smoothfactor = 15 # Mirthe used 2 or 4 # check if cll continued here from last end point if not j == 0 and start1[j] == ends[j - 1]: # yes we continued ppart = centerline1[: -1] # cut last but do not cut first point as this is midpoint else: # do not use first points, as they are influenced by user selected points ppart = centerline1[1:-1] for p in ppart: centerline.append(p) # if last stent or stent does not continue with next start-endpoint if j == stentnr - 1 or not ends[j] == start1[j + 1]: # store non-smoothed for vis allcenterlines_nosmooth.append(centerline) pp = smooth_centerline(centerline, n=smoothfactor) # add pp to list allcenterlines.append(pp) # list with PointSet per centerline self.allcenterlines = allcenterlines # add pp as nodes for i, p in enumerate(pp): p_as_tuple = tuple(p.flat) nodes.add_node(p_as_tuple) nodes_total.add_node(p_as_tuple) # add pp as one edge so that pathpoints are in fixed order pstart = tuple(pp[0].flat) pend = tuple(pp[-1].flat) nodes.add_edge(pstart, pend, path=pp) nodes_total.add_edge(pstart, pend, path=pp) # add final centerline nodes model to list centerlines.append(nodes) # ========= Maaike ======= ## Store segmentation to disk # Build struct s2 = vv.ssdf.new() s2.sampling = s.sampling s2.origin = s.origin s2.stenttype = m.stenttype s2.croprange = m.croprange for key in dir(m): if key.startswith('meta'): suffix = key[4:] s2['meta' + suffix] = m['meta' + suffix] s2.what = what s2.params = s.params #reg s2.paramsseeds = m.params s2.stentType = 'nellix' s2.StartPoints = StartPoints s2.EndPoints = EndPoints # keep centerlines as pp also [Maaike] s2.ppallCenterlines = allcenterlines for k in range(len(allcenterlines)): suffix = str(k) pp = allcenterlines[k] s2['ppCenterline' + suffix] = pp s3 = copy.deepcopy(s2) s3['model'] = nodes_total.pack() # Store model for each centerline for j in range(len(centerlines)): suffix = str(j) model = centerlines[j] s2['model' + suffix] = model.pack() # Save model with seperate centerlines. filename = '%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname, 'centerline_' + what) vv.ssdf.save(os.path.join(basedir, ptcode, filename), s2) print('saved to disk as {}.'.format(filename)) # Save model with combined centerlines filename = '%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname, 'centerline_total_' + what) vv.ssdf.save(os.path.join(basedir, ptcode, filename), s3) print('saved to disk as {}.'.format(filename)) # remove intermediate centerline points # start1 = map(tuple, start1) # ends = map(tuple, ends) startpoints_clean = copy.deepcopy(start1) endpoints_clean = copy.deepcopy(ends) duplicates = list(set(start1) & set(ends)) for i in range(len(duplicates)): startpoints_clean.remove(duplicates[i]) endpoints_clean.remove(duplicates[i]) #Visualize f = vv.figure(10) vv.clf() a1 = vv.subplot(121) a1.daspect = 1, 1, -1 vv.plot(ppp, ms='.', ls='', alpha=0.6, mw=2) for j in range(len(startpoints_clean)): vv.plot(PointSet(list(startpoints_clean[j])), ms='.', ls='', mc='g', mw=20) # startpoint green vv.plot(PointSet(list(endpoints_clean[j])), ms='.', ls='', mc='r', mw=20) # endpoint red for j in range(len(allcenterlines)): vv.plot(allcenterlines[j], ms='.', ls='', mw=10, mc='y') vv.title('Centerlines and seed points') vv.xlabel('x (mm)') vv.ylabel('y (mm)') vv.zlabel('z (mm)') # for j in range(len(allcenterlines_nosmooth)): # vv.plot(allcenterlines_nosmooth[j], ms='o', ls='', mw=10, mc='c', alpha=0.6) a2 = vv.subplot(122) a2.daspect = 1, 1, -1 vv.plot(ppp, ms='.', ls='', alpha=0.6, mw=2) # vv.volshow(s.vol, clim=clim, renderStyle = 'mip') t = show_ctvolume(s.vol, axis=a2, showVol='ISO', clim=(0, 2500), isoTh=250, removeStent=False, climEditor=True) label = pick3d(vv.gca(), s.vol) for j in range(len(startpoints_clean)): vv.plot(PointSet(list(startpoints_clean[j])), ms='.', ls='', mc='g', mw=20, alpha=0.6) # startpoint green vv.plot(PointSet(list(endpoints_clean[j])), ms='.', ls='', mc='r', mw=20, alpha=0.6) # endpoint red for j in range(len(allcenterlines)): vv.plot(allcenterlines[j], ms='o', ls='', mw=10, mc='y', alpha=0.6) # show midpoints (e.g. duplicates) if vismids: for p in duplicates: vv.plot(p[0], p[1], p[2], mc='m', ms='o', mw=10, alpha=0.6) a2.axis.visible = False vv.title('Centerlines and seed points') a1.camera = a2.camera f.eventKeyDown.Bind( lambda event: _utils_GUI.RotateView(event, [a1, a2])) f.eventKeyDown.Bind( lambda event: _utils_GUI.ViewPresets(event, [a1, a2])) # Pick node for midpoint to redo get_centerline self.pickedCLLpoint = _utils_GUI.Event_pick_graph_point( nodes_total, s.vol, label, nodesOnly=True) # x,y,z # use key p to select point #=============================================================================== vv.figure(11) vv.gca().daspect = 1, 1, -1 t = show_ctvolume(s.vol, showVol='ISO', clim=(0, 2500), isoTh=250, removeStent=False, climEditor=True) label2 = pick3d(vv.gca(), s.vol) for j in range(len(startpoints_clean)): vv.plot(PointSet(list(startpoints_clean[j])), ms='.', ls='', mc='g', mw=20, alpha=0.6) # startpoint green vv.plot(PointSet(list(endpoints_clean[j])), ms='.', ls='', mc='r', mw=20, alpha=0.6) # endpoint red vv.xlabel('x (mm)') vv.ylabel('y (mm)') vv.zlabel('z (mm)') #=============================================================================== ## Make model dynamic (and store/overwrite to disk) import pirt from stentseg.motion.dynamic import incorporate_motion_nodes, incorporate_motion_edges # Load deforms filename = '%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname, 'deforms') s1 = vv.ssdf.load(os.path.join(basedir, ptcode, filename)) deformkeys = [] for key in dir(s1): if key.startswith('deform'): deformkeys.append(key) deforms = [s1[key] for key in deformkeys] deforms = [ pirt.DeformationFieldBackward(*fields) for fields in deforms ] for i in range(len(deforms)): deforms[i]._field_sampling = tuple(s1.sampling) paramsreg = s1.params # Load model s2 = loadmodel(basedir, ptcode, ctcode, cropname, 'centerline_' + what) s3 = loadmodel(basedir, ptcode, ctcode, cropname, 'centerline_total_' + what) # Combine ... for key in dir(s2): if key.startswith('model'): incorporate_motion_nodes(s2[key], deforms, s.origin) incorporate_motion_edges(s2[key], deforms, s.origin) model = s2[key] s2[key] = model.pack() # Combine ... for key in dir(s3): if key.startswith('model'): incorporate_motion_nodes(s3[key], deforms, s.origin) incorporate_motion_edges(s3[key], deforms, s.origin) model = s3[key] s3[key] = model.pack() # Save s2.paramsreg = paramsreg filename = '%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname, 'centerline_' + what + '_deforms') vv.ssdf.save(os.path.join(basedir, ptcode, filename), s2) print('saved to disk as {}.'.format(filename)) # Save s3.paramsreg = paramsreg filename = '%s_%s_%s_%s.ssdf' % ( ptcode, ctcode, cropname, 'centerline_total_' + what + '_deforms') vv.ssdf.save(os.path.join(basedir, ptcode, filename), s3) print('saved to disk as {}.'.format(filename))
renal1_and_cl_point[0]) # Main outcome 1: distance 2nd ring valleys to renal # Main outcome 2: migration 2nd ring valleys from discharge to 1, 6, 12 months ## Visualize f = vv.figure(2) vv.clf() f.position = 0.00, 22.00, 1920.00, 1018.00 alpha = 0.5 if ctcode2: a1 = vv.subplot(121) else: a1 = vv.gca() show_ctvolume(vol1, model1, showVol=showVol, clim=clim0, isoTh=isoTh) pick3d(vv.gca(), vol1) model1.Draw(mc='b', mw=10, lc='g') vm = vv.mesh(modelmesh1) vm.faceColor = 'g' # m = vv.mesh(vessel1) # m.faceColor = (1,0,0, alpha) # red # vis vessel, centerline, renal origo, peaks valleys R1 vv.plot(ppvessel1, ms='.', ls='', mc='r', alpha=0.2, mw=7, axes=a1) # vessel vv.plot(PointSet(list(c1_start1)), ms='.', ls='', mc='g', mw=18, axes=a1) # start1 vv.plot([e[0] for e in c1_ends], [e[1] for e in c1_ends], [e[2] for e in c1_ends], ms='.', ls='', mc='b',
model = s.model model2 = model.copy() # Load static CT image to add as reference s2 = loadvol(basedir, ptcode, ctcode, cropname, 'avgreg') vol = s2.vol f = vv.figure(1) vv.clf() a = vv.subplot(1, 2, 1) a.axis.axisColor = 1, 1, 1 a.axis.visible = False a.bgcolor = 0, 0, 0 a.daspect = 1, 1, -1 t = vv.volshow(vol, clim=(0, 2500), renderStyle='mip') label = pick3d(a, vol) # model.Draw(mc='b', mw = 10, lc='g') vv.xlabel('x (mm)') vv.ylabel('y (mm)') vv.zlabel('z (mm)') vv.title('Model for LSPEAS %s - %s' % (ptcode[7:], ctcode)) # get hooks and struts model_struts, model_hooks, model_R1R2, model_h_s, model_noHooks = get_model_struts( model, nstruts=8) model_R1R2.Draw(mc='r', mw=10, lc='r') model_noHooks.Draw(mc='b', mw=10, lc='b') model_struts.Draw(mc='y', mw=10, lc='y') a2 = vv.subplot(1, 2, 2) a2.axis.axisColor = 1, 1, 1