def compareGraphsVisually(graph1, graph2, fig=None): """ compareGraphsVisually(graph1, graph2, fig=None) Show the two graphs together in a figure. Matched nodes are indicated by lines between them. """ # Get figure if isinstance(fig,int): fig = vv.figure(fig) elif fig is None: fig = vv.figure() # Prepare figure and axes fig.Clear() a = vv.gca() a.cameraType = '3d'; a.daspectAuto = False # Draw both graphs graph1.Draw(lc='b', mc='b') graph2.Draw(lc='r', mc='r') # Set the limits a.SetLimits() # Make a line from the edges pp = Pointset(3) for node in graph1: if hasattr(node, 'match') and node.match is not None: pp.append(node); pp.append(node.match) # Plot edges vv.plot(pp, lc='g', ls='+')
def OnDown(self, event): """ Called when the mouse is pressed down in the axes. """ # Only process left mouse button if event.button != 1: return False # Store location self._active = Point(event.x2d, event.y2d) # Clear temp line object if self._line1: self._line1.Destroy() # Create line objects tmp = Pointset(2) tmp.append(self._active) tmp.append(self._active) self._line1 = vv.plot(tmp, lc="r", lw="1", axes=self._a, axesAdjust=0) # Draw self._a.Draw() # Prevent dragging by indicating the event needs no further handling return True
def OnDown(self, event): """ Called when the mouse is pressed down in the axes. """ # Only process left mouse button if event.button != 1: return False # Store location self._active = Point(event.x2d, event.y2d) # Clear temp line object if self._line1: self._line1.Destroy() # Create line objects tmp = Pointset(2) tmp.append(self._active) tmp.append(self._active) self._line1 = vv.plot(tmp, lc='r', lw='1', axes=self._a, axesAdjust=0) # Draw self._a.Draw() # Prevent dragging by indicating the event needs no further handling return True
def test_gui(self): pp = Pointset(3) pp.append(0, 0, 0) pp.append(0, 1, 0) pp.append(1, 2, 0) pp.append(0, 2, 1) # Create all solids vv.solidBox((0, 0, 0)) sphere = vv.solidSphere((3, 0, 0)) cone = vv.solidCone((6, 0, 0)) # a cone with 4 faces is a pyramid pyramid = vv.solidCone((9, 0, 0), N=4) vv.solidCylinder((0, 3, 0), (1, 1, 2)) ring = vv.solidRing((3, 3, 0)) vv.solidTeapot((6, 3, 0)) vv.solidLine(pp+Point(9, 3, 0), radius=0.2) # Make the ring green ring.faceColor = 'g' # Make the sphere dull sphere.specular = 0 sphere.diffuse = 0.4 # Show lines in yellow pyramid pyramid.faceColor = 'r' pyramid.edgeShading = 'plain' # Colormap example N = cone._vertices.shape[0] cone.SetValues(np.linspace(0, 1, N)) cone.colormap = vv.CM_JET
def __init__(self): # Create figure and axes vv.figure() self._a = a = vv.gca() vv.title("Hold mouse to draw lines. Use 'rgbcmyk' and '1-9' keys.") # Set axes a.SetLimits((0,1), (0,1)) a.cameraType = '2d' a.daspectAuto = False a.axis.showGrid = True # Init variables needed during drawing self._active = None self._pp = Pointset(2) # Create null and empty line objects self._line1 = None self._line2 = vv.plot(vv.Pointset(2), ls='+', lc='c', lw='2', axes=a) # Bind to events a.eventMouseDown.Bind(self.OnDown) a.eventMouseUp.Bind(self.OnUp) a.eventMotion.Bind(self.OnMotion) a.eventKeyDown.Bind(self.OnKey)
def on_down(self, event): if event.button != 1: return False if not vv.KEY_SHIFT in event.modifiers: return False # Store location self._active = Point(event.x2d, event.y2d) # Clear any line object for l in self._lines: l.Destroy() # Create line objects tmp = Pointset(2) tmp.append(self._active) tmp.append(self._active) l1 = vv.plot(tmp, lc='g', lw='3', axes=self._a2, axesAdjust=0) l2 = vv.plot(tmp[:1], ls='', ms='.', mc='g', axes=self._a2, axesAdjust=0) self._lines = [l1, l2] # Draw self._a2.Draw() # Prevent dragging by indicating the event needs no further handling return True
def on_key(event): """KEY commands for user interaction UP/DOWN = show/hide nodes ENTER = show edge and attribute values [select 2 nodes] DELETE = remove edge [select 2 nodes] CTRL = replace intially created ringparts ESCAPE = FINISH: refine, smooth """ if event.key == vv.KEY_DOWN: # hide nodes t1.visible = False t2.visible = False t3.visible = False for node_point in node_points: node_point.visible = False if event.key == vv.KEY_UP: # show nodes for node_point in node_points: node_point.visible = True if event.key == vv.KEY_ENTER: select1 = selected_nodes[0].node select2 = selected_nodes[1].node c, ct, p, l = _utils_GUI.get_edge_attributes(model, select1, select2) # visualize edge and deselect nodes selected_nodes[1].faceColor = 'b' selected_nodes[0].faceColor = 'b' selected_nodes.clear() _utils_GUI.set_edge_labels(t1,t2,t3,ct,c,l) a = vv.gca() view = a.GetView() pp = Pointset(p) # visvis meshes do not work with PointSet line = vv.solidLine(pp, radius = 0.2) line.faceColor = 'y' a.SetView(view) if event.key == vv.KEY_DELETE: # remove edge assert len(selected_nodes) == 2 select1 = selected_nodes[0].node select2 = selected_nodes[1].node c, ct, p, l = _utils_GUI.get_edge_attributes(model, select1, select2) model.remove_edge(select1, select2) # visualize removed edge, show keys and deselect nodes selected_nodes[1].faceColor = 'b' selected_nodes[0].faceColor = 'b' selected_nodes.clear() _utils_GUI.set_edge_labels(t1,t2,t3,ct,c,l) a = vv.gca() view = a.GetView() pp = Pointset(p) line = vv.solidLine(pp, radius = 0.2) line.faceColor = 'r' a.SetView(view) if event.key == vv.KEY_CONTROL: # replace intially created ringparts ringparts(ringpart=ringpart) figparts()
def Pack(self): """ Pack() Pack the contents in an ssdf struct, such that it can be stored. """ # If nodelist is empty, ndim defaults to two ndim = 2 # Get a list of all edges cc = self.GetEdges() # Check whether the nodes are homogenous, otherwise we cannot store if len(self): ndim = self[0].ndim for node in self: if not node.ndim == ndim: raise ValueError('All nodes should have the same dimension.') # Init struct struct = ssdf.new() # Create array of nodes pp = Pointset(ndim) for node in self: pp.append(node) struct.nodes = pp.data # Create the edges tmp = np.zeros((len(cc), 2), dtype=np.uint32) for i in range(len(cc)): c = cc[i] tmp[i,0] = c._i1 tmp[i,1] = c._i2 struct.edges = tmp # Store the properties of the edges. The propRefs array # Does contain redundant data, but it can be stored efficiently # because the compression handles that... allProps = b'' propRefs = np.zeros((len(cc), 2), dtype=np.uint32) for i in range(len(cc)): tmp = serializeProps(cc[i].props) propRefs[i, 0] = len(allProps) propRefs[i, 1] = len(allProps) + len(tmp) allProps += tmp struct.edgePropRefs = propRefs if allProps: struct.edgeProps = np.frombuffer( allProps, dtype=np.uint8) else: struct.edgeProps = np.zeros( (0,), dtype=np.uint8) # done return struct
def Pack(self): """ Pack() Pack the contents in an ssdf struct, such that it can be stored. """ # If nodelist is empty, ndim defaults to two ndim = 2 # Get a list of all edges cc = self.GetEdges() # Check whether the nodes are homogenous, otherwise we cannot store if len(self): ndim = self[0].ndim for node in self: if not node.ndim == ndim: raise ValueError('All nodes should have the same dimension.') # Init struct struct = ssdf.new() # Create array of nodes pp = Pointset(ndim) for node in self: pp.append(node) struct.nodes = pp.data # Create the edges tmp = np.zeros((len(cc), 2), dtype=np.uint32) for i in range(len(cc)): c = cc[i] tmp[i,0] = c._i1 tmp[i,1] = c._i2 struct.edges = tmp # Store the properties of the edges. The propRefs array # Does contain redundant data, but it can be stored efficiently # because the compression handles that... allProps = '' propRefs = np.zeros((len(cc), 2), dtype=np.uint32) for i in range(len(cc)): tmp = serializeProps(cc[i].props) propRefs[i, 0] = len(allProps) propRefs[i, 1] = len(allProps) + len(tmp) allProps += tmp struct.edgePropRefs = propRefs if allProps: struct.edgeProps = np.frombuffer( allProps, dtype=np.uint8) else: struct.edgeProps = np.zeros( (0,), dtype=np.uint8) # done return struct
def OnMotion(self, event): """ Called when the mouse is moved in the axes. """ if self._active and self._line1: # Update line tmp = Pointset(2) tmp.append(self._active) tmp.append(event.x2d, event.y2d) self._line1.SetPoints(tmp) # Draw self._a.Draw()
def apply(self, event=None): # Get axes a1 = self._a1 # Get sampling grid_sampling = self._sampling, self._sampling * 2**self._levels # Create grid tmp = self._pp[:, 0] tmp.shape = (tmp.size, 1) pp = Pointset(tmp) grid1 = SplineGrid.from_points_multiscale( (self._fieldSize, ), grid_sampling, pp.data, self._pp[:, 1]) # Get copy grid2 = grid1.copy() # Freeze edges self.freeze_edges(grid1) # # Create second grid # grid2 = SplineGrid.from_field(grid.get_field(), grid.grid_sampling) # grid3 = SplineGrid.from_field_multiscale(grid.get_field(), grid.grid_sampling) # Get grid points ppg1 = Pointset(2) ppg2 = Pointset(2) for gx in range(grid1.grid_shape[0]): ppg1.append((gx - 1) * grid1.grid_sampling, grid1.knots[gx]) ppg2.append((gx - 1) * grid2.grid_sampling, grid2.knots[gx]) # Get field field = grid1.get_field() #field2 = grid2.get_field() #field3 = grid3.get_field() # Delete objects in scene for ob in a1.wobjects: if ob is not self._line1 and not isinstance( ob, vv.axises.BaseAxis): ob.Destroy() # Draw vv.plot(ppg1, ls='', ms='x', mc='b', mw=9, axes=a1, axesAdjust=False) vv.plot(ppg2, ls='', ms='x', mc='c', mw=9, axes=a1, axesAdjust=False) vv.plot(np.arange(0, field.size), field, ls='-', lc='g', lw=3, axes=a1, axesAdjust=False)
def Unpack(self, struct): """ Unpack(struct) Load the contents from an ssdf struct. This removes the old nodes and edges. """ # clear first self.Clear() # First create nodes pp = Pointset(struct.nodes) for p in pp: self.AppendNode(p) # Make backward compatible if hasattr(struct, 'connections'): struct.edges = struct.connections struct.edgePropRefs = struct.connectionPropRefs struct.edgeProps = struct.connectionProps # Create the edges for i in range( struct.edges.shape[0] ): # Get serialized property and convert it i1 = struct.edgePropRefs[i,0] i2 = struct.edgePropRefs[i,1] tmp = struct.edgeProps[i1:i2].tostring() props = deserializeProps(tmp) # Get which nodes belong to it and create edge object i1 = int(struct.edges[i,0]) i2 = int(struct.edges[i,1]) c = self.CreateEdge(i1, i2, *props)
def deserializeProps(bb): """ deserializeProps(bb) Set the properties by decoding them from a bytes string. """ # Init list of properties props = [] # Decode the string i = 0 while i < len(bb): if bb[i] == b'\x00'[0]: # float tmp = np.frombuffer( bb[i+1:i+5], dtype=np.float32 ) props.append( float(tmp) ) i += 5 elif bb[i] == b'\x01'[0]: # int tmp = np.frombuffer( bb[i+1:i+5], dtype=np.int32 ) props.append( int(tmp) ) i += 5 elif bb[i] == b'\x09'[0]: n = np.frombuffer( bb[i+1:i+5], dtype=np.int32 ) ndim = bb[i+5] if not isinstance(ndim, int): ndim = ord(ndim) nbytes = n*ndim*4 tmp = np.frombuffer( bb[i+6:i+6+nbytes], dtype=np.float32 ) tmp.shape = n, ndim props.append( Pointset(tmp) ) i += 6 + nbytes # Return properties return props
def __init__(self): # Create figure and axes vv.figure() self._a = a = vv.gca() vv.title("Hold mouse to draw lines. Use 'rgbcmyk' and '1-9' keys.") # Set axes a.SetLimits((0, 1), (0, 1)) a.cameraType = "2d" a.daspectAuto = False a.axis.showGrid = True # Init variables needed during drawing self._active = None self._pp = Pointset(2) # Create null and empty line objects self._line1 = None self._line2 = vv.plot(vv.Pointset(2), ls="+", lc="c", lw="2", axes=a) # Bind to events a.eventMouseDown.Bind(self.OnDown) a.eventMouseUp.Bind(self.OnUp) a.eventMotion.Bind(self.OnMotion) a.eventKeyDown.Bind(self.OnKey)
def Draw(self, mc='g', lc='y', mw=7, lw=0.6, alpha=0.5, axes=None): """ Draw(mc='g', lc='y', mw=7, lw=0.6, alpha=0.5, axes=None) Draw nodes and edges. """ # We can only draw if we have any nodes if not len(self): return # Make sure there are elements in the lines list while len(self._lines)<2: self._lines.append(None) # Build node list if mc and mw: pp = Pointset(self[0].ndim) for p in self: pp.append(p) # Draw nodes, reuse if possible! l_node = self._lines[0] if l_node and len(l_node._points) == len(pp): l_node.SetPoints(pp) elif l_node: l_node.Destroy() l_node = None if l_node is None: l_node = vv.plot(pp, ls='', ms='o', mc=mc, mw=mw, axesAdjust=0, axes=axes, alpha=alpha) self._lines[0] = l_node # For simplicity, always redraw edges if self._lines[1] is not None: self._lines[1].Destroy() # Build edge list if lc and lw: cc = self.GetEdges() # Draw edges pp = Pointset(self[0].ndim) for c in cc: pp.append(c.end1); pp.append(c.end2) tmp = vv.plot(pp, ms='', ls='+', lc=lc, lw=lw, axesAdjust=0, axes=axes, alpha=alpha) self._lines[1] = tmp
def value(self, value): self._value = [] for dataset in value: if len(dataset)>0: if isinstance(dataset[0], list) or isinstance(dataset[0], tuple) : self._value.append( Pointset( np.array(dataset) ) ) else: self._value.append( dataset ) self.refresh()
def create_mesh(graph, radius=1.0, fullPaths=True): """ Create a polygonal model from the stent and return it as a visvis.BaseMesh object. To draw the mesh, instantiate a normal mesh using vv.Mesh(vv.gca(), thisMesh). """ from visvis.processing import lineToMesh, combineMeshes from visvis import Pointset # lineToMesh does not like the new PointSet class # Init list of meshes meshes = [] for n1, n2 in graph.edges(): # Obtain path of edge and make mesh if fullPaths: path = graph.edge[n1][n2]['path'] path = Pointset(path) # Make a visvis pointset else: path = Pointset(3) path.append(n1) path.append(n2) meshes.append(lineToMesh(path, radius, 8)) # Combine meshes and return if meshes: return combineMeshes(meshes) else: return None
def __init__(self): # Setup visualization self._fig = fig = vv.figure() self._a1 = a1 = vv.subplot(111) # Init pointset with control points self._pp = Pointset(2) # Init lines to show control points self._line1 = vv.plot(self._pp, ls='', ms='.', mc='r', mw=11, axes=a1) self._line1.hitTest = True # Init grid properties self._fieldSize = 100 self._sampling = 10 self._levels = 5 # Member to indicate the point being dragged (as an index) self._active = None # Bind to events a1.eventDoubleClick.Bind(self.on_doubleclick) self._line1.eventDoubleClick.Bind(self.on_doubleclick_line) self._line1.eventMouseDown.Bind(self.on_down_line) self._line1.eventMouseUp.Bind(self.on_up_line) a1.eventMotion.Bind(self.on_motion) fig.eventKeyDown.Bind(self.on_key_down) print( 'Use left/right to control #levels and up/down to control grid sampling.' ) # Init self.apply() a1.daspectAuto = False a1.SetLimits() a1.axis.showGrid = True
def on_motion(self, event): if self._active and self._lines: # Update line tmp = Pointset(2) tmp.append(self._active) tmp.append(event.x2d, event.y2d) l1 = self._lines[0] l1.SetPoints(tmp) # Draw self._a2.Draw()
def remove_stent_from_volume(vol, graph, stripSize=5, stripSizeZ=None): """ Give the high intensity voxels that belong to the stent a lower value, so that the stent appears to be "removed". This is for visualization purposes only. Makes use of known paths in graph model. """ from visvis import Pointset vol2 = vol.copy() for n1, n2 in graph.edges(): path = graph.edge[n1][n2]['path'] path = Pointset(path) # Make a visvis pointset if stripSizeZ is None: stripSizeZ = stripSize // 2 # floor division for point in path: z, y, x = vol2.point_to_index(point) vol2[z - stripSizeZ:z + stripSizeZ + 1, y - stripSize:y + stripSize + 1, x - stripSize:x + stripSize + 1] = 0 # remove less in z direction to not remove 3rd ring/calcifications -> stripSize2 return vol2
def vis_spared_edges(graph, radius=0.6, axes=None): """ in step 3 with anacondaRing, prune_redundant spares strong triangle edges. visualize with a model """ from visvis import Pointset if graph is None: return if axes is None: a = vv.gca() else: axes.MakeCurrent() a = vv.gca() for (n1, n2) in graph.edges(): if graph.node[n1].get('spared', False) and \ graph.node[n2].get('spared', False): p = graph.edge[n1][n2]['path'] pp = Pointset(p) line = vv.solidLine(pp, radius=radius) line.faceColor = 'y'
def on_key(event): """KEY commands for user interaction 'UP/DOWN = show/hide nodes' 'DELETE = remove edge [select 2 nodes] or pop node [select 1 node] ' 'or remove seed in nodes1 closest to [picked point]' 'PageDown = remove graph posterior (y-axis) to [picked point] (use for spine seeds)' 'ALT = clean graph: remove residual clusters, pop, corner' 'CTRL+SHIFT = add [picked point] (SHIFT+R-click) as seed' """ global label global node_points global sd if event.key == vv.KEY_DOWN: # hide nodes t1.visible = False t2.visible = False t3.visible = False for node_point in node_points: node_point.visible = False if event.key == vv.KEY_UP: # show nodes for node_point in node_points: node_point.visible = True if event.key == vv.KEY_DELETE: if len(selected_nodes) == 0: # remove node closest to picked point node = _utils_GUI.snap_picked_point_to_graph(sd._nodes1, vol, label, nodesOnly=True) sd._nodes1.remove_node(node) view = a1.GetView() a1.Clear() label = DrawModelAxes(vol, sd._nodes1, a1, clim=clim, showVol=showVol, removeStent=False) a1.SetView(view) if len(selected_nodes) == 2: # remove edge select1 = selected_nodes[0].node select2 = selected_nodes[1].node c = sd._nodes3.edge[select1][select2]['cost'] ct = sd._nodes3.edge[select1][select2]['ctvalue'] path = sd._nodes3.edge[select1][select2]['path'] l = stentgraph._edge_length(sd._nodes3, select1, select2) sd._nodes3.remove_edge(select1, select2) stentgraph.pop_nodes(sd._nodes3) # pop residual nodes # Visualize removed edge, show keys and deselect nodes selected_nodes[1].faceColor = 'b' selected_nodes[0].faceColor = 'b' selected_nodes.clear() t1.text = 'Edge ctvalue: \b{%1.2f HU}' % ct t2.text = 'Edge cost: \b{%1.7f }' % c t3.text = 'Edge length: \b{%1.2f mm}' % l t1.visible = True t2.visible = True t3.visible = True view = a3.GetView() pp = Pointset(path) line = vv.solidLine(pp, radius=0.2) line.faceColor = 'r' # a3.SetView(view) if len(selected_nodes) == 1: # pop node select1 = selected_nodes[0].node stentgraph._pop_node(sd._nodes3, select1) # asserts degree == 2 selected_nodes[0].faceColor = 'w' selected_nodes.clear() if event.key == vv.KEY_ALT: # ALT will FINISH model stentgraph.prune_clusters(sd._nodes3, 3) #remove residual nodes/clusters stentgraph.pop_nodes(sd._nodes3) stentgraph.add_corner_nodes(sd._nodes3, th=sd._params.graph_angleVector, angTh=sd._params.graph_angleTh) # Create mesh and visualize view = a3.GetView() a3.Clear() DrawModelAxes(vol, sd._nodes3, a3, meshColor=meshColor, clim=clim, showVol=showVol, lc='b', mw=8, lw=0.2) _utils_GUI.vis_spared_edges(sd._nodes3) a3.SetView(view) print( '----DO NOT FORGET TO SAVE THE MODEL TO DISK; RUN _SAVE_SEGMENTATION----' ) if event.text == 'n': # add picked seed to nodes_1 coord2 = get_picked_seed(vol, label) sd._nodes1.add_node(tuple(coord2)) view = a1.GetView() point = vv.plot(coord2[0], coord2[1], coord2[2], mc='b', ms='o', mw=8, alpha=0.5, axes=a1) a1.SetView(view) if event.text == 'p': # protect node from pop pickedNode = _utils_GUI.snap_picked_point_to_graph(sd._nodes1, vol, label, nodesOnly=True) sd._nodes1.add_node(pickedNode, nopop=True) sd._nodes2.add_node(pickedNode, nopop=True) view = a1.GetView() point = vv.plot(pickedNode[0], pickedNode[1], pickedNode[2], mc='y', ms='o', mw=8, alpha=0.5, axes=a1) a1.SetView(view) # now rerun step 3 if event.key == vv.KEY_PAGEDOWN: # remove false seeds posterior to picked point, e.g. for spine try: _utils_GUI.remove_nodes_by_selected_point(sd._nodes3, vol, a3, label, clim, showVol=showVol) except ValueError: # false nodes already cleaned by Step3 pass _utils_GUI.remove_nodes_by_selected_point(sd._nodes2, vol, a2, label, clim, showVol=showVol) label = _utils_GUI.remove_nodes_by_selected_point(sd._nodes1, vol, a1, label, clim, showVol=showVol) if event.text == '1': # redo step1 view = a1.GetView() a1.Clear() a2.Clear() a3.Clear() sd._params = p sd.Step1() label = DrawModelAxes(vol, sd._nodes1, a1, clim=clim, showVol=showVol, removeStent=False) # lc, mc a1.SetView(view) if event.text == '2': # redo step2 and 3 view = a2.GetView() a2.Clear() a3.Clear() sd._params = p sd.Step2() sd.Step3(cleanNodes=cleanNodes) DrawModelAxes(vol, sd._nodes2, a2, clim=clim, showVol=showVol, removeStent=False) DrawModelAxes(vol, sd._nodes3, a3, meshColor=meshColor, clim=clim, showVol=showVol, removeStent=False) a2.SetView(view) if event.text == '3': view = a3.GetView() a3.Clear() sd._params = p sd.Step3(cleanNodes=cleanNodes) DrawModelAxes(vol, sd._nodes3, a3, meshColor=meshColor, clim=clim, showVol=showVol, removeStent=False) node_points = _utils_GUI.interactive_node_points(sd._nodes3, scale=0.6) _utils_GUI.node_points_callbacks(node_points, selected_nodes, pick=False) a3.SetView(view) if event.text == 's': # SAVE SEGMENTATION # make centerline points of segmentation paths_as_pp = points_from_edges_in_graph(sd._nodes3, type='order') ringpoints = paths_as_pp[0].T # Get graph model model = sd._nodes3 seeds = sd._nodes1 Draw = sd.Draw # Build struct s2 = vv.ssdf.new() # We do not need croprange, but keep for reference 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 s2.model = model.pack() s2.seeds = seeds.pack() s2.Draw = Draw s2.ringpoints = ringpoints #s2.mesh = ssdf.new() # Save savedir = select_dir( r'C:\Users\Gebruiker\Google Drive\Afstuderen\Rings') filename = '%s_%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname, 'model' + what, ring) ssdf.save(os.path.join(savedir, filename), s2) print('saved to disk in {} as {}.'.format(savedir, filename))
class DeformByHand: """ DeformByHand(im, grid_sampling=40) Demo application to deform a 2D image by hand using a spline grid. Use the grid property to obtain the deformation grid. Use the run() method to wait for the user to close the figure. """ 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() def on_key_down(self, event): # Update level if event.key == vv.KEY_UP: self._sampling += 2 elif event.key == vv.KEY_DOWN: self._sampling -= 2 elif event.key == vv.KEY_RIGHT: self._levels += 1 elif event.key == vv.KEY_LEFT: self._levels -= 1 # elif event.text.upper() == 'M': self._multiscale = not self._multiscale elif event.text.upper() == 'I': self._injective += 0.4 if self._injective > 0.8: self._injective = -0.8 elif event.text.upper() == 'E': self._frozenedge = not self._frozenedge elif event.text.upper() == 'F': self._forward = not self._forward # reset global field if self._forward: self.DeformationField = DeformationFieldForward else: self.DeformationField = DeformationFieldBackward self._field1 = self.DeformationField(FieldDescription(self._im)) # elif event.key == vv.KEY_ESCAPE: self._pp1.clear() self._pp2.clear() self.apply() elif event.text == ' ': self.apply_deform() # else: return # Correct if self._sampling < 1: self._sampling = 1 self.apply() def on_down(self, event): if event.button != 1: return False if not vv.KEY_SHIFT in event.modifiers: return False # Store location self._active = Point(event.x2d, event.y2d) # Clear any line object for l in self._lines: l.Destroy() # Create line objects tmp = Pointset(2) tmp.append(self._active) tmp.append(self._active) l1 = vv.plot(tmp, lc='g', lw='3', axes=self._a2, axesAdjust=0) l2 = vv.plot(tmp[:1], ls='', ms='.', mc='g', axes=self._a2, axesAdjust=0) self._lines = [l1, l2] # Draw self._a2.Draw() # Prevent dragging by indicating the event needs no further handling return True def on_motion(self, event): if self._active and self._lines: # Update line tmp = Pointset(2) tmp.append(self._active) tmp.append(event.x2d, event.y2d) l1 = self._lines[0] l1.SetPoints(tmp) # Draw self._a2.Draw() def on_up(self, event): if self._active is None: return False # Get points p1 = self._active p2 = Point(event.x2d, event.y2d) # Add! self._pp1.append(p1) self._pp2.append(p2) # We're done with this one self._active = None # Clear any line object for l in self._lines: l.Destroy() # Apply self.apply() def apply_deform(self): # Apply current point-wise deformation # Compose deformations self._field1 = self._field1.compose(self._field2) # Clear points self._pp1.clear() self._pp2.clear() # Update self.apply() def apply(self): # Get sampling grid_sampling = self._sampling, self._sampling*2**self._levels # Init field and deform if not self._pp1: # Unit deform deform = self.DeformationField(FieldDescription(self._im)) elif self._multiscale: deform = self.DeformationField.from_points_multiscale(self._im, grid_sampling, self._pp1.data, self._pp2.data, injective=self._injective, frozenedge=self._frozenedge) else: DeformationGrid = DeformationGridForward if not self._forward: DeformationGrid = DeformationGridBackward grid = DeformationGrid.from_points(self._im, self._sampling, self._pp1.data, self._pp2.data, injective=self._injective, frozenedge=self._frozenedge) deform = grid.as_deformation_field() # Store grid field0 = self.DeformationField(FieldDescription(self._im)) self._field2 = deform field3 = self._field1.compose(self._field2) # Deform im2 = self._field1.apply_deformation(self._im) im3 = field3.apply_deformation(self._im) # Update imagesf self._t2.SetData(im2) self._t3.SetData(im3) # Update grids for a, field in zip( [self._a4, self._a5, self._a6], [field0, self._field1, field3] ): a.Clear() field.show(a, False) a.axis.visible = False # Update lines tmp = Pointset(2) for i in range(len(self._pp1)): tmp.append(self._pp1[i]) tmp.append(self._pp2[i]) self._line1.SetPoints(self._pp1) self._line2.SetPoints(tmp) # Draw self._a2.Draw() # Show text text1 = 'B-spline (S) with sampling %i (U/D) and %i levels (L/R).' % ( self._sampling, self._levels) text2 = 'Multiscale %i (M), injective %1.1f (I), frozen edge %i (E), forward %i (F).' % ( self._multiscale, self._injective, self._frozenedge, self._forward) # Display and apply self._text1.text = text1 self._text2.text = text2 @property def field(self): return self._field1 def run(self): # Setup detecting closing of figure self._closed = False def callback(event): self._closed = True self._fig.eventClose.Bind(callback) while not self._closed: time.sleep(0.02) vv.processEvents() self.apply_deform()
class Drawer: def __init__(self): # Create figure and axes vv.figure() self._a = a = vv.gca() vv.title("Hold mouse to draw lines. Use 'rgbcmyk' and '1-9' keys.") # Set axes a.SetLimits((0, 1), (0, 1)) a.cameraType = "2d" a.daspectAuto = False a.axis.showGrid = True # Init variables needed during drawing self._active = None self._pp = Pointset(2) # Create null and empty line objects self._line1 = None self._line2 = vv.plot(vv.Pointset(2), ls="+", lc="c", lw="2", axes=a) # Bind to events a.eventMouseDown.Bind(self.OnDown) a.eventMouseUp.Bind(self.OnUp) a.eventMotion.Bind(self.OnMotion) a.eventKeyDown.Bind(self.OnKey) def OnKey(self, event): """ Called when a key is pressed down in the axes. """ if event.text and event.text.lower() in "rgbcmywk": self._line2.lc = event.text.lower() else: try: tickness = int(event.text) except Exception: tickness = 0 if tickness > 0: self._line2.lw = tickness def OnDown(self, event): """ Called when the mouse is pressed down in the axes. """ # Only process left mouse button if event.button != 1: return False # Store location self._active = Point(event.x2d, event.y2d) # Clear temp line object if self._line1: self._line1.Destroy() # Create line objects tmp = Pointset(2) tmp.append(self._active) tmp.append(self._active) self._line1 = vv.plot(tmp, lc="r", lw="1", axes=self._a, axesAdjust=0) # Draw self._a.Draw() # Prevent dragging by indicating the event needs no further handling return True def OnMotion(self, event): """ Called when the mouse is moved in the axes. """ if self._active and self._line1: # Update line tmp = Pointset(2) tmp.append(self._active) tmp.append(event.x2d, event.y2d) self._line1.SetPoints(tmp) # Draw self._a.Draw() def OnUp(self, event): """ Called when the mouse is released (when first pressed down in the axes). """ # Only if a point is active if self._active is None: return False # Get points p1 = self._active p2 = Point(event.x2d, event.y2d) # Add! self._pp.append(p1) self._pp.append(p2) # We're done with this one self._active = None # Clear temp line object if self._line1: self._line1.Destroy() self._line1 = None # Update lines self._line2.SetPoints(self._pp) # Draw self._a.Draw()
plain color, colormaps and texture. On the website, this example also demonstrates the fly camera to fly through the mesh objects. """ import numpy as np import visvis as vv from visvis import Point, Pointset vv.figure() a = vv.gca() # Define points for the line pp = Pointset(3) pp.append(0, 0, 0) pp.append(0, 1, 0) pp.append(1, 2, 0) pp.append(0, 2, 1) # Create all solids box = vv.solidBox((0, 0, 0)) sphere = vv.solidSphere((3, 0, 0)) cone = vv.solidCone((6, 0, 0)) pyramid = vv.solidCone((9, 0, 0), N=4) # a cone with 4 faces is a pyramid cylinder = vv.solidCylinder((0, 3, 0), (1, 1, 2)) ring = vv.solidRing((3, 3, 0)) teapot = vv.solidTeapot((6, 3, 0)) line = vv.solidLine(pp + Point(9, 3, 0), radius=0.2)
It also shows the different techniques to apply color to the meshes using plain color, colormaps and texture. On the website, this example also demonstrates the fly camera to fly through the mesh objects. """ import numpy as np import visvis as vv from visvis import Point, Pointset vv.figure() a = vv.gca() # Define points for the line pp = Pointset(3) pp.append(0,0,0); pp.append(0,1,0); pp.append(1,2,0); pp.append(0,2,1) # Create all solids box = vv.solidBox((0,0,0)) sphere = vv.solidSphere((3,0,0)) cone = vv.solidCone((6,0,0)) pyramid = vv.solidCone((9,0,0), N=4) # a cone with 4 faces is a pyramid cylinder = vv.solidCylinder((0,3,0),(1,1,2)) ring = vv.solidRing((3,3,0)) teapot = vv.solidTeapot((6,3,0)) line = vv.solidLine(pp+Point(9,3,0), radius = 0.2) # Let's put a face on that cylinder # This works because 2D texture coordinates are automatically generated for # the sphere, cone, cylinder and ring.
class Drawer: def __init__(self): # Create figure and axes vv.figure() self._a = a = vv.gca() vv.title("Hold mouse to draw lines. Use 'rgbcmyk' and '1-9' keys.") # Set axes a.SetLimits((0,1), (0,1)) a.cameraType = '2d' a.daspectAuto = False a.axis.showGrid = True # Init variables needed during drawing self._active = None self._pp = Pointset(2) # Create null and empty line objects self._line1 = None self._line2 = vv.plot(vv.Pointset(2), ls='+', lc='c', lw='2', axes=a) # Bind to events a.eventMouseDown.Bind(self.OnDown) a.eventMouseUp.Bind(self.OnUp) a.eventMotion.Bind(self.OnMotion) a.eventKeyDown.Bind(self.OnKey) def OnKey(self, event): """ Called when a key is pressed down in the axes. """ if event.text and event.text.lower() in 'rgbcmywk': self._line2.lc = event.text.lower() else: try: tickness = int(event.text) except Exception: tickness = 0 if tickness > 0: self._line2.lw = tickness def OnDown(self, event): """ Called when the mouse is pressed down in the axes. """ # Only process left mouse button if event.button != 1: return False # Store location self._active = Point(event.x2d, event.y2d) # Clear temp line object if self._line1: self._line1.Destroy() # Create line objects tmp = Pointset(2) tmp.append(self._active) tmp.append(self._active) self._line1 = vv.plot(tmp, lc='r', lw='1', axes=self._a, axesAdjust=0) # Draw self._a.Draw() # Prevent dragging by indicating the event needs no further handling return True def OnMotion(self, event): """ Called when the mouse is moved in the axes. """ if self._active and self._line1: # Update line tmp = Pointset(2) tmp.append(self._active) tmp.append(event.x2d, event.y2d) self._line1.SetPoints(tmp) # Draw self._a.Draw() def OnUp(self, event): """ Called when the mouse is released (when first pressed down in the axes). """ # Only if a point is active if self._active is None: return False # Get points p1 = self._active p2 = Point(event.x2d, event.y2d) # Add! self._pp.append(p1) self._pp.append(p2) # We're done with this one self._active = None # Clear temp line object if self._line1: self._line1.Destroy() self._line1 = None # Update lines self._line2.SetPoints(self._pp) # Draw self._a.Draw()
def on_key(event): """KEY commands for user interaction UP/DOWN = show/hide nodes DELETE = remove edge [select 2 nodes] or pop node [select 1 node] or remove seed sd._nodes1 closest to [picked point] ALT = SHOW RESULT after pop """ global node_points if event.key == vv.KEY_DOWN: # hide nodes for node_point in node_points: node_point.visible = False t3.visible = False if event.key == vv.KEY_UP: # show nodes for node_point in node_points: node_point.visible = True if event.key == vv.KEY_DELETE: if len(selected_nodes) == 2: # remove edge select1 = selected_nodes[0].node select2 = selected_nodes[1].node c, ct, p, l = _utils_GUI.get_edge_attributes( model, select1, select2) t3.text = 'Edge length: \b{%1.2f mm}' % l t3.visible = True model.remove_edge(select1, select2) # visualize removed edge, show keys and deselect nodes selected_nodes[1].faceColor = 'b' selected_nodes[0].faceColor = 'b' selected_nodes.clear() a = vv.gca() view = a.GetView() pp = Pointset(p) line = vv.solidLine(pp, radius=0.2) line.faceColor = 'r' a.SetView(view) if len(selected_nodes) == 1: # pop node or remove select1 = selected_nodes[0].node if select1 in model.nodes_with_selfloops(): model.remove_node[select1] else: stentgraph._pop_node(model, select1) # asserts degree == 2 selected_nodes[0].faceColor = 'w' selected_nodes.clear() if event.text == 's': # additional smooth stentgraph.smooth_paths(model, 2) node_points = reDrawModel(vol, model, selected_nodes=selected_nodes) if event.text == 'e': # smooth selected edge edgegraph = stentgraph.StentGraph() #empty graph select1 = selected_nodes[0].node select2 = selected_nodes[1].node edge_info = model.edge[select1][select2] edgegraph.add_edge(select1, select2, **edge_info) stentgraph.smooth_paths(edgegraph, 4) model.edge[select1][select2]['path'] = edgegraph.edge[select1][ select2]['path'] node_points = reDrawModel(vol, model, selected_nodes=selected_nodes) if event.text == 'w': for n in selected_nodes: n.faceColor = 'b' selected_nodes.clear() if event.key == vv.KEY_ALT: # ALT will POP nodes stentgraph.pop_nodes(model) node_points = reDrawModel(vol, model, selected_nodes=selected_nodes) if event.text == 'q': ax = vv.gca() view = ax.GetView() _utils_GUI.interactiveClusterRemoval(model) ax.SetView(view) if event.key == vv.KEY_ESCAPE: g = model_dynamic(model, deforms, origin) node_points = reDrawModel(vol, g, selected_nodes=selected_nodes) s.model = g print('Done, model dynamic') # Save back filename = '%s_%s_%s_%s.ssdf' % (ptcode, ctcode, cropname, modelname) # pack all graphs in ssdf for save for key in dir(s): if key.startswith('model'): s[key] = s[key].pack() if key.startswith('seeds'): s[key] = s[key].pack() ssdf.save(os.path.join(basedir, ptcode, filename), s) print('Model saved dynamic to disk in {} as {}.'.format( basedir, filename))
def on_key(event): """KEY commands for user interaction UP/DOWN = show/hide nodes ENTER = restore edge [select 2 nodes] DELETE = remove edge [select 2 ndoes] or pop node [select 1 node]' ALT = clean graph: pop, crossings, corner ESCAPE = FINISH: refine, smooth """ global node_points global nodes3copy if event.key == vv.KEY_DOWN: # hide nodes t1.visible = False t2.visible = False t3.visible = False for node_point in node_points: node_point.visible = False if event.key == vv.KEY_UP: # show nodes for node_point in node_points: node_point.visible = True if event.key == vv.KEY_ENTER: # restore edge assert len(selected_nodes) == 2 select1 = selected_nodes[0].node select2 = selected_nodes[1].node c = sd._nodes2.edge[select1][select2]['cost'] ct = sd._nodes2.edge[select1][select2]['ctvalue'] p = sd._nodes2.edge[select1][select2]['path'] sd._nodes3.add_edge(select1, select2, cost=c, ctvalue=ct, path=p) l = stentgraph._edge_length(sd._nodes3, select1, select2) # Visualize restored edge and deselect nodes selected_nodes[1].faceColor = 'b' selected_nodes[0].faceColor = 'b' selected_nodes.clear() t1.text = 'Edge ctvalue: \b{%1.2f HU}' % ct t2.text = 'Edge cost: \b{%1.7f }' % c t3.text = 'Edge length: \b{%1.2f mm}' % l t1.visible = True t2.visible = True t3.visible = True view = a3.GetView() pp = Pointset(p) # visvis meshes do not work with PointSet line = vv.solidLine(pp, radius=0.2) line.faceColor = 'g' a3.SetView(view) if event.key == vv.KEY_DELETE: if len(selected_nodes) == 2: # remove edge select1 = selected_nodes[0].node select2 = selected_nodes[1].node c = sd._nodes3.edge[select1][select2]['cost'] ct = sd._nodes3.edge[select1][select2]['ctvalue'] p = sd._nodes3.edge[select1][select2]['path'] l = stentgraph._edge_length(sd._nodes3, select1, select2) sd._nodes3.remove_edge(select1, select2) # visualize removed edge, show keys and deselect nodes selected_nodes[1].faceColor = 'b' selected_nodes[0].faceColor = 'b' selected_nodes.clear() t1.text = 'Edge ctvalue: \b{%1.2f HU}' % ct t2.text = 'Edge cost: \b{%1.7f }' % c t3.text = 'Edge length: \b{%1.2f mm}' % l t1.visible = True t2.visible = True t3.visible = True view = a3.GetView() pp = Pointset(p) line = vv.solidLine(pp, radius=0.2) line.faceColor = 'r' a3.SetView(view) if len(selected_nodes) == 1: # pop node select1 = selected_nodes[0].node stentgraph._pop_node(sd._nodes3, select1) # asserts degree == 2 selected_nodes[0].faceColor = 'w' selected_nodes.clear() if event.key == vv.KEY_ALT: #backup to restore nodes3copy = sd._nodes3.copy() # clean nodes if stentType == 'anacondaRing': stentgraph.add_nodes_at_crossings(sd._nodes3) stentgraph.pop_nodes( sd._nodes3) # pop before corner detect or angles can not be found stentgraph.add_corner_nodes(sd._nodes3, th=sd._params.graph_angleVector, angTh=sd._params.graph_angleTh) stentgraph.pop_nodes( sd._nodes3 ) # because removing edges/add nodes can create degree 2 nodes stentgraph.prune_tails(sd._nodes3, sd._params.graph_trimLength) stentgraph.prune_clusters(sd._nodes3, 3) #remove residual nodes/clusters # visualize result view = a3.GetView() a3.Clear() DrawModelAxes(vol, sd._nodes3, a3, clim=clim, showVol=showVol, mw=8, lw=0.2, climEditor=False) node_points = _utils_GUI.interactive_node_points(sd._nodes3, scale=0.6) _utils_GUI.node_points_callbacks(node_points, selected_nodes, pick=False) a3.SetView(view) print('----Press ESCAPE to FINISH model----') if event.text == 'u': # undo and restore nodes3 sd._nodes3 = nodes3copy view = a3.GetView() a3.Clear() DrawModelAxes(vol, sd._nodes3, a3, clim=clim, showVol=showVol, mw=8, lw=0.2, climEditor=False) node_points = _utils_GUI.interactive_node_points(sd._nodes3, scale=0.6) _utils_GUI.node_points_callbacks(node_points, selected_nodes, pick=False) a3.SetView(view) if event.key == vv.KEY_ESCAPE: #backup to restore nodes3copy = sd._nodes3.copy() # ESCAPE will FINISH model stentgraph.pop_nodes(sd._nodes3) sd._nodes3 = sd._RefinePositions(sd._nodes3) # subpixel locations stentgraph.smooth_paths(sd._nodes3, 4) # Create mesh and visualize view = a3.GetView() a3.Clear() DrawModelAxes(vol, sd._nodes3, a3, meshColor='g', clim=clim, showVol=showVol, lc='w', mw=8, lw=0.2, climEditor=False) node_points = _utils_GUI.interactive_node_points(sd._nodes3, scale=0.6) _utils_GUI.node_points_callbacks(node_points, selected_nodes, pick=False) a3.SetView(view) print( '----DO NOT FORGET TO SAVE THE MODEL TO DISK; RUN _SAVE_SEGMENTATION----' ) if event.text == 'r': # restore this node pickedNode = _utils_GUI.snap_picked_point_to_graph( sd._nodes2, vol, label, nodesOnly=True) # x,y,z sd._nodes3.add_node(pickedNode) view = a3.GetView() a3.Clear() DrawModelAxes(vol, sd._nodes3, a3, clim=clim, showVol=showVol, mw=8, lw=0.2, climEditor=False) node_points = _utils_GUI.interactive_node_points(sd._nodes3, scale=0.6) _utils_GUI.node_points_callbacks(node_points, selected_nodes, pick=False) a3.SetView(view) if event.text == 's': # additional smooth stentgraph.smooth_paths(sd._nodes3, 2) view = a3.GetView() a3.Clear() DrawModelAxes(vol, sd._nodes3, a3, clim=clim, showVol=showVol, mw=8, lw=0.2, climEditor=False) node_points = _utils_GUI.interactive_node_points(sd._nodes3, scale=0.6) _utils_GUI.node_points_callbacks(node_points, selected_nodes, pick=False) a3.SetView(view) if event.text == 'e': # smooth selected edge edgegraph = stentgraph.StentGraph() #empty graph select1 = selected_nodes[0].node select2 = selected_nodes[1].node edge_info = sd._nodes3.edge[select1][select2] edgegraph.add_edge(select1, select2, **edge_info) stentgraph.smooth_paths(edgegraph, 4) sd._nodes3.edge[select1][select2]['path'] = edgegraph.edge[select1][ select2]['path'] view = a3.GetView() a3.Clear() DrawModelAxes(vol, sd._nodes3, a3, clim=clim, showVol=showVol, mw=8, lw=0.2, climEditor=False) node_points = _utils_GUI.interactive_node_points(sd._nodes3, 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) a3.SetView(view) if event.text == 'w': for n in selected_nodes: n.faceColor = 'b' selected_nodes.clear() if event.text == 'q': view = a3.GetView() _utils_GUI.interactiveClusterRemoval(sd._nodes3) a3.SetView(view)
def compareGraphs(graph1, graph2, maxDist): """ compareGraphs(graph1, graph2, maxDist) Compare two graphs to produce a matching score. Returns a MatchingScore instance. Matching and not-matching edges are counted to obtain a matching score. nodes should be closer than maxDist to be considered 'at the same location'. """ # Check graphs if not graph1 or not graph2: print('Warning: one of the graphs to compare is empty.') return MatchingScore(0,1,0) #raise ValueError('One of the graphs to compare is empty.') # Create pointsets of the nodes pp1 = Pointset(3) for node in graph1: pp1.append(node) pp2 = Pointset(3) for node in graph2: pp2.append(node) # Match the nodes of graph1 to graph2 for node in graph1: dists = node.distance(pp2) i, = np.where(dists==dists.min()) node.match = None if len(i): i = int(i[0]) dist = float(dists[i]) if dist < maxDist: node.match = graph2[i] # if not hasattr(node, 'dontCare'): # node.dontCare = False # Match the nodes of graph2 to graph1 for node in graph2: dists = node.distance(pp1) i, = np.where(dists==dists.min()) node.match = None if len(i): i = int(i[0]) dist = float(dists[i]) if dist < maxDist: node.match = graph1[i] # if not hasattr(node, 'dontCare'): # node.dontCare = False # Init amounts nmatch1, nmatch2, nmiss, nwrong = 0,0,0,0 # Count matches and wrongs for c in graph1.GetEdges(): end1 = c.end1.match end2 = c.end2.match if end1 and end2: if end1 in end2.GetNeighbours(): nmatch1 += 1 continue # elif c.end1.dontCare or c.end2.dontCare: # continue nwrong += 1 # todo: use dontCare 'beleid' or not? # Count matches and misses for c in graph2.GetEdges(): end1 = c.end1.match end2 = c.end2.match if end1 and end2: if end1 in end2.GetNeighbours(): nmatch2 += 1 continue # elif c.end1.dontCare or c.end2.dontCare: # continue nmiss += 1 # Compose score return MatchingScore(nmatch1, nmiss, nwrong)
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()
class SplineByHand: """ SplineByHand() Demo application to influence a 1D spline grid using control points. """ def __init__(self): # Setup visualization self._fig = fig = vv.figure() self._a1 = a1 = vv.subplot(111) # Init pointset with control points self._pp = Pointset(2) # Init lines to show control points self._line1 = vv.plot(self._pp, ls='', ms='.', mc='r', mw=11, axes=a1) self._line1.hitTest = True # Init grid properties self._fieldSize = 100 self._sampling = 10 self._levels = 5 # Member to indicate the point being dragged (as an index) self._active = None # Bind to events a1.eventDoubleClick.Bind(self.on_doubleclick) self._line1.eventDoubleClick.Bind(self.on_doubleclick_line) self._line1.eventMouseDown.Bind(self.on_down_line) self._line1.eventMouseUp.Bind(self.on_up_line) a1.eventMotion.Bind(self.on_motion) fig.eventKeyDown.Bind(self.on_key_down) print( 'Use left/right to control #levels and up/down to control grid sampling.' ) # Init self.apply() a1.daspectAuto = False a1.SetLimits() a1.axis.showGrid = True def on_key_down(self, event): # Update level if event.key == vv.KEY_UP: self._sampling += 1 elif event.key == vv.KEY_DOWN: self._sampling -= 1 elif event.key == vv.KEY_RIGHT: self._levels += 1 elif event.key == vv.KEY_LEFT: self._levels -= 1 else: return # Correct if self._sampling < 1: self._sampling = 1 # Apply and print print('Using B-spline grid with %i sampling and %i levels.' % (self._sampling, self._levels)) self.apply() def on_doubleclick(self, event): # On axes # Get new point p = Point(event.x2d, event.y2d) # Add to pointset self._pp.append(p) self._line1.SetPoints(self._pp) # Apply self.apply() def on_doubleclick_line(self, event): # On axes # Get closest point dists = Point(event.x2d, event.y2d).distance(self._pp) I, = np.where(dists == dists.min()) if not len(I): return False # Remove from pointset self._pp.Pop(I[0]) self._line1.SetPoints(self._pp) # Apply self._a1.Draw() self.apply() def on_down_line(self, event): # On line instance if event.button != 1: return False # Get closest point dists = Point(event.x2d, event.y2d).distance(self._pp) I, = np.where(dists == dists.min()) if not len(I): return False # Store self._active = I[0] # Prevent dragging by indicating the event needs no further handling return True def on_motion(self, event): if self._active is None: return False # Update line self._pp[self._active] = Point(event.x2d, event.y2d) self._line1.SetPoints(self._pp) # Draw self._a1.Draw() def on_up_line(self, event): if self._active is None: return False # Update point self.on_motion(event) # Deactivate self._active = None # Apply self.apply() def apply(self, event=None): # Get axes a1 = self._a1 # Get sampling grid_sampling = self._sampling, self._sampling * 2**self._levels # Create grid tmp = self._pp[:, 0] tmp.shape = (tmp.size, 1) pp = Pointset(tmp) grid1 = SplineGrid.from_points_multiscale( (self._fieldSize, ), grid_sampling, pp.data, self._pp[:, 1]) # Get copy grid2 = grid1.copy() # Freeze edges self.freeze_edges(grid1) # # Create second grid # grid2 = SplineGrid.from_field(grid.get_field(), grid.grid_sampling) # grid3 = SplineGrid.from_field_multiscale(grid.get_field(), grid.grid_sampling) # Get grid points ppg1 = Pointset(2) ppg2 = Pointset(2) for gx in range(grid1.grid_shape[0]): ppg1.append((gx - 1) * grid1.grid_sampling, grid1.knots[gx]) ppg2.append((gx - 1) * grid2.grid_sampling, grid2.knots[gx]) # Get field field = grid1.get_field() #field2 = grid2.get_field() #field3 = grid3.get_field() # Delete objects in scene for ob in a1.wobjects: if ob is not self._line1 and not isinstance( ob, vv.axises.BaseAxis): ob.Destroy() # Draw vv.plot(ppg1, ls='', ms='x', mc='b', mw=9, axes=a1, axesAdjust=False) vv.plot(ppg2, ls='', ms='x', mc='c', mw=9, axes=a1, axesAdjust=False) vv.plot(np.arange(0, field.size), field, ls='-', lc='g', lw=3, axes=a1, axesAdjust=False) #vv.plot(field2, ls=':', lc=(0,0.5,0), lw=6, axes=a1, axesAdjust=False) #vv.plot(field3, ls=':', lc=(0,0.75,0), lw=6, axes=a1, axesAdjust=False) def freeze_edges(self, grid): # Store grid for debugging self._grid = grid # Freeze left edge grid.knots[1] = 0 grid.knots[0] = -grid.knots[2] # c0, c1, c2, c3 = pirt.get_cubic_spline_coefs(0, 'B') # k1, k2, k3 = grid.knots[0], grid.knots[1], grid.knots[2] # grid.knots[0] = 0 # grid.knots[1]=0 # grid.knots[2]= ) # Calculate t factor field_edge = (grid.field_shape[0] - 1) * grid.field_sampling[0] grid_edge = (grid.grid_shape[0] - 4) * grid.grid_sampling t = (field_edge - grid_edge) / grid.grid_sampling # Get coefficients c0, c1, c2, c3 = interp.get_cubic_spline_coefs(t, 'B') # Freeze right edge # grid.knots[-3] = t*grid.knots[-3] # + (1-t)*0 # k0, k1 = grid.knots[-4], grid.knots[-3] # grid.knots[-2] = t**2 * (k1-k0) + t*(2*k0-k1) - k0 # k0, k1, k2, k3 = grid.knots[-4], grid.knots[-3], grid.knots[-2], grid.knots[-1] # grid.knots[-1] = -(k0*c0 + k1*c1 + k2*c2)/c3 grid.knots[-3] = t * grid.knots[-3] # + (1-t)*0 grid.knots[-1] = 0 k0, k1 = grid.knots[-4], grid.knots[-3] grid.knots[-2] = -(k0 * c0 + k1 * c1) / c2
def apply(self): # Get sampling grid_sampling = self._sampling, self._sampling*2**self._levels # Init field and deform if not self._pp1: # Unit deform deform = self.DeformationField(FieldDescription(self._im)) elif self._multiscale: deform = self.DeformationField.from_points_multiscale(self._im, grid_sampling, self._pp1.data, self._pp2.data, injective=self._injective, frozenedge=self._frozenedge) else: DeformationGrid = DeformationGridForward if not self._forward: DeformationGrid = DeformationGridBackward grid = DeformationGrid.from_points(self._im, self._sampling, self._pp1.data, self._pp2.data, injective=self._injective, frozenedge=self._frozenedge) deform = grid.as_deformation_field() # Store grid field0 = self.DeformationField(FieldDescription(self._im)) self._field2 = deform field3 = self._field1.compose(self._field2) # Deform im2 = self._field1.apply_deformation(self._im) im3 = field3.apply_deformation(self._im) # Update imagesf self._t2.SetData(im2) self._t3.SetData(im3) # Update grids for a, field in zip( [self._a4, self._a5, self._a6], [field0, self._field1, field3] ): a.Clear() field.show(a, False) a.axis.visible = False # Update lines tmp = Pointset(2) for i in range(len(self._pp1)): tmp.append(self._pp1[i]) tmp.append(self._pp2[i]) self._line1.SetPoints(self._pp1) self._line2.SetPoints(tmp) # Draw self._a2.Draw() # Show text text1 = 'B-spline (S) with sampling %i (U/D) and %i levels (L/R).' % ( self._sampling, self._levels) text2 = 'Multiscale %i (M), injective %1.1f (I), frozen edge %i (E), forward %i (F).' % ( self._multiscale, self._injective, self._frozenedge, self._forward) # Display and apply self._text1.text = text1 self._text2.text = text2
def on_key(event): """KEY commands for user interaction 'UP/DOWN = show/hide nodes' 'DELETE = remove edge [select 2 nodes] or pop node [select 1 node] ' 'or remove seed in nodes1 closest to [picked point]' 'p = remove seeds posterior (y-axis) to [picked point] (use for spine seeds)' 'o = remove seeds anterior (y-axis) to [picked point]' 'i = remove seeds proximal (z-axis) to [picked point]' 'k = remove seeds distal (z-axis) to [picked point]' 'l = remove seeds left (x-axis) to [picked point]' 'j = remove seeds right (x-axis) to [picked point]' 'ALT = clean graph: remove residual clusters, pop, corner' 'PageUp= protect node closest to picked point in nodes1 axes, no pop 'n = add [picked point] (SHIFT+R-click) as seed' '1 = redo step 1; 2 = redo step 2; 3 = redo step 3' 'z/x/a/d = axis invisible/visible/rotate' """ global label global node_points global sd if event.key == vv.KEY_DOWN: # hide nodes t1.visible = False t2.visible = False t3.visible = False if 'node_points' in globals(): for node_point in node_points: node_point.visible = False if event.key == vv.KEY_UP: # show nodes if 'node_points' in globals(): for node_point in node_points: node_point.visible = True if event.key == vv.KEY_DELETE: if len(selected_nodes) == 0: # remove node closest to picked point node = _utils_GUI.snap_picked_point_to_graph(sd._nodes1, vol, label, nodesOnly=True) sd._nodes1.remove_node(node) view = a1.GetView() a1.Clear() label = DrawModelAxes(vol, sd._nodes1, a1, clim=clim, showVol=showVol, removeStent=False) a1.SetView(view) if len(selected_nodes) == 2: # remove edge select1 = selected_nodes[0].node select2 = selected_nodes[1].node c = sd._nodes3.edge[select1][select2]['cost'] ct = sd._nodes3.edge[select1][select2]['ctvalue'] path = sd._nodes3.edge[select1][select2]['path'] l = stentgraph._edge_length(sd._nodes3, select1, select2) sd._nodes3.remove_edge(select1, select2) stentgraph.pop_nodes(sd._nodes3) # pop residual nodes # Visualize removed edge, show keys and deselect nodes selected_nodes[1].faceColor = 'b' selected_nodes[0].faceColor = 'b' selected_nodes.clear() t1.text = 'Edge ctvalue: \b{%1.2f HU}' % ct t2.text = 'Edge cost: \b{%1.7f }' % c t3.text = 'Edge length: \b{%1.2f mm}' % l t1.visible = True t2.visible = True t3.visible = True view = a3.GetView() pp = Pointset(path) line = vv.solidLine(pp, radius = 0.2) line.faceColor = 'r' a3.SetView(view) if len(selected_nodes) == 1: # pop node select1 = selected_nodes[0].node stentgraph._pop_node(sd._nodes3, select1) # asserts degree == 2 selected_nodes[0].faceColor = 'w' selected_nodes.clear() if event.key == vv.KEY_ALT: # ALT will FINISH model stentgraph.prune_clusters(sd._nodes3, 3) #remove residual nodes/clusters stentgraph.pop_nodes(sd._nodes3) stentgraph.add_corner_nodes(sd._nodes3, th=sd._params.graph_angleVector, angTh=sd._params.graph_angleTh) # Create mesh and visualize view = a3.GetView() a3.Clear() DrawModelAxes(vol, sd._nodes3, a3, meshColor=meshColor, clim=clim, showVol=showVol, lc='g', mw=8, lw=0.2) # _utils_GUI.vis_spared_edges(sd._nodes3) a3.SetView(view) print('----DO NOT FORGET TO SAVE THE MODEL TO DISK; RUN _SAVE_SEGMENTATION----') if event.text == 'n': # add picked seed to nodes_1 coord2 = get_picked_seed(vol, label) sd._nodes1.add_node(tuple(coord2)) view = a1.GetView() point = vv.plot(coord2[0], coord2[1], coord2[2], mc= 'b', ms = 'o', mw= 8, alpha=0.5, axes=a1) a1.SetView(view) if event.key == vv.KEY_PAGEUP: # protect node from pop pickedNode = _utils_GUI.snap_picked_point_to_graph(sd._nodes1, vol, label, nodesOnly=True) sd._nodes1.add_node(pickedNode, nopop = True) sd._nodes2.add_node(pickedNode, nopop = True) view = a1.GetView() point = vv.plot(pickedNode[0], pickedNode[1], pickedNode[2], mc= 'y', ms = 'o', mw= 8, alpha=0.5, axes=a1) a1.SetView(view) # now rerun step 3 if event.text == 'p': # remove false seeds posterior to picked point, e.g. for spine _utils_GUI.remove_nodes_by_selected_point(sd._nodes2, vol, a2, label, clim, location='posterior', showVol=showVol) label = _utils_GUI.remove_nodes_by_selected_point(sd._nodes1, vol, a1, label, clim, location='posterior', showVol=showVol) if event.text == 'o': # remove seeds prox to selected point _utils_GUI.remove_nodes_by_selected_point(sd._nodes2, vol, a1, label, clim, location='anterior', showVol=showVol) label = _utils_GUI.remove_nodes_by_selected_point(sd._nodes1, vol, a1, label, clim, location='anterior', showVol=showVol) if event.text == 'i': # remove seeds prox to selected point _utils_GUI.remove_nodes_by_selected_point(sd._nodes2, vol, a1, label, clim, location='proximal', showVol=showVol) label = _utils_GUI.remove_nodes_by_selected_point(sd._nodes1, vol, a1, label, clim, location='proximal', showVol=showVol) if event.text == 'k': # remove seeds dist to selected point _utils_GUI.remove_nodes_by_selected_point(sd._nodes2, vol, a1, label, clim, location='distal', showVol=showVol) label = _utils_GUI.remove_nodes_by_selected_point(sd._nodes1, vol, a1, label, clim, location='distal', showVol=showVol) if event.text == 'l': # remove seeds left to selected point _utils_GUI.remove_nodes_by_selected_point(sd._nodes2, vol, a1, label, clim, location='left', showVol=showVol) label = _utils_GUI.remove_nodes_by_selected_point(sd._nodes1, vol, a1, label, clim, location='left', showVol=showVol) if event.text == 'j': # remove seeds right to selected point _utils_GUI.remove_nodes_by_selected_point(sd._nodes2, vol, a1, label, clim, location='right', showVol=showVol) label = _utils_GUI.remove_nodes_by_selected_point(sd._nodes1, vol, a1, label, clim, location='right', showVol=showVol) if event.text == '1': # redo step1 view = a1.GetView() a1.Clear(); a2.Clear(); a3.Clear() sd._params = p sd.Step1() label = DrawModelAxes(vol, sd._nodes1, a1, clim=clim, showVol=showVol, removeStent=False) # lc, mc a1.SetView(view) if event.text == '2': # redo step2 view = a2.GetView() a2.Clear(); a3.Clear() sd._params = p sd.Step2() DrawModelAxes(vol, sd._nodes2, a2, clim=clim, showVol=showVol,removeStent=False) a2.SetView(view) if event.text == '3': # redo step3 view = a3.GetView() a3.Clear() sd._params = p sd.Step3(cleanNodes=True) DrawModelAxes(vol, sd._nodes3, a3, meshColor=meshColor, clim=clim, showVol=showVol,removeStent=False) node_points = _utils_GUI.interactive_node_points(sd._nodes3, scale=0.6) _utils_GUI.node_points_callbacks(node_points, selected_nodes, pick=False) a3.SetView(view)
#!/usr/bin/env python import numpy as np import visvis as vv from visvis import Point, Pointset app = vv.use() # create random points a = np.random.normal(size=(1000, 3)) pp = Pointset(a) pp *= Point(2, 5, 1) # prepare axes a = vv.gca() a.cameraType = '3d' a.daspectAuto = False # draw points l = vv.plot(pp, ms='.', mc='r', mw='9', ls='', mew=0) l.alpha = 0.1 app.Run()