Ejemplo n.º 1
0
    def Step3(self):
        """ Step3()
        Process graph to remove unwanted edges.
        """

        # Check if we can go
        if self._vol is None or self._params is None:
            raise ValueError('Data or params not yet given.')
        if self._nodes2 is None:
            raise ValueError('Edges not yet calculated.')

        # Get nodes and params
        #nodes = stentgraph.StentGraph()
        #nodes.unpack( self._nodes2.pack() )
        nodes = self._nodes2.copy()
        params = self._params

        # Init times
        t_start = time.time()
        t_clean = 0

        print('Step3 in StentDirect_test is indeed used :)')

        # Iteratively prune the graph. The order of operations should
        # not matter too much, although in practice there is a
        # difference. In particular the prune_weak and prune_redundant
        # have a similar function and should be executed in this order.
        cur_edges = 0
        count = 0
        while cur_edges != nodes.number_of_edges():
            count += 1
            cur_edges = nodes.number_of_edges()
            ene = params.graph_expectedNumberOfEdges

            stentgraph.prune_very_weak(nodes, params.graph_weakThreshold)
            stentgraph.prune_weak(nodes, ene, params.graph_strongThreshold)
            stentgraph.prune_redundant(nodes, params.graph_strongThreshold)
            stentgraph.prune_clusters(nodes, params.graph_minimumClusterSize)
            stentgraph.prune_tails(nodes, params.graph_trimLength)

        stentgraph.pop_nodes(nodes)
        stentgraph.add_corner_nodes(nodes)
        stentgraph.smooth_paths(nodes)

        t0 = time.time() - t_start
        tmp = "Reduced to %i edges, "
        tmp += "which took %1.2f s (%i iters)"
        print(tmp % (nodes.number_of_edges(), t0, count))
        print("****************************************")

        # Finish
        self._nodes3 = nodes
        if self._draw:
            self.Draw(3)

        return nodes
Ejemplo n.º 2
0
    def test_prune_clusters(self):
        # Create two small cliques
        graph = StentGraph()
        graph.add_edge(1, 2, cost=2, ctvalue=50)
        graph.add_edge(2, 3, cost=2, ctvalue=50)
        graph.add_edge(3, 1, cost=2, ctvalue=50)
        #
        graph.add_edge(4, 5, cost=2, ctvalue=50)
        graph.add_edge(5, 6, cost=2, ctvalue=50)
        graph.add_edge(6, 7, cost=2, ctvalue=50)
        graph.add_edge(7, 4, cost=2, ctvalue=50)

        # Connect them
        graph.add_edge(1, 4, cost=3, ctvalue=50)

        # Also add loose node
        graph.add_nodes_from([101, 102])

        # Remove cliques and check that nothing happened
        prune_clusters(graph, 4)
        assert graph.number_of_edges() == 8
        assert graph.number_of_nodes() == 7

        # Remove connection
        graph.remove_edge(1, 4)

        # Remove cliques and check that one clique is removed
        prune_clusters(graph, 4)
        assert graph.number_of_edges() == 4
        assert graph.number_of_nodes() == 4

        # Remove cliques and check that one clique is removed
        prune_clusters(graph, 5)
        assert graph.number_of_edges() == 0
        assert graph.number_of_nodes() == 0
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
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))
Ejemplo n.º 5
0
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)