-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathvmtksurfaceconnectivityselector.py
235 lines (187 loc) · 9.34 KB
/
vmtksurfaceconnectivityselector.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
#!/usr/bin/env python
## Program: VMTK
## Module: $RCSfile: vmtksurfaceconnectivityselector.py,v $
## Language: Python
## Date: $Date: 2018/04/03 12:49:59 $
## Version: $Revision: 0.1 $
## Copyright (c) Richard Izzo, Luca Antiga. All rights reserved.
## See LICENCE file for details.
## This software is distributed WITHOUT ANY WARRANTY; without even
## the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
## PURPOSE. See the above copyright notices for more information.
from __future__ import absolute_import #NEEDS TO STAY AS TOP LEVEL MODULE FOR Py2-3 COMPATIBILITY
import vtk
import sys
from vmtk import vmtkrenderer
from vmtk import pypes
class vmtkPickPointSeedSelector(object):
def __init__(self):
self.PrintError = None
self.PrintLog = None
self.InputText = None
self.OutputText = None
self.InputInfo = None
self._OutputPolyDataList = []
self.vmtkRenderer = None
self.OwnRenderer = 0
self.Script = None
self.CurrentPickedActor = None
self.CurrentPickedPolyData = None
self.PastPickedActorList = []
def UndoCallback(self, obj):
# The execution order is extremly important in this method. Do not change if possible.
self.vmtkRenderer.RenderWindow.Render()
# First remove the vtkPolyDataObject from the list where it is being stored.
# by default we remove the last element selected first
self._OutputPolyDataList.pop()
# the actor instance is stored within the PastPickedActorList object. We tell the renderer
# to remove the actor from the scene, then remove that actor from the list.
self.vmtkRenderer.Renderer.RemoveActor(self.PastPickedActorList[-1])
self.PastPickedActorList.pop()
# update the scene in the render window
self.vmtkRenderer.RenderWindow.Render()
return
def PickCallback(self, obj):
picker = vtk.vtkPointPicker()
eventPosition = self.vmtkRenderer.RenderWindowInteractor.GetEventPosition()
result = picker.Pick(float(eventPosition[0]),float(eventPosition[1]),0.0,self.vmtkRenderer.Renderer)
# We treat result as a boolean value (which can also be nonetype if a selection outside the render windw is made)
# If the value of result is False or None, then an invalid actor was selected in the scene.
if result is None:
return
elif result == 0:
return
# find the value of "RegionId" stored in the vtkPolyData PointData array. This is a unique number
# which is generated for each connected surface point by the allRegionConnectivity
# vtkPolyDataConnectivityFilter function
pickedPointId = picker.GetPointId()
self.CurrentPickedActor = picker.GetActor()
self.CurrentPickedPolyData = self.CurrentPickedActor.GetMapper().GetInputAsDataSet()
regionId = self.CurrentPickedPolyData.GetPointData().GetArray('RegionId').GetValue(pickedPointId)
# extract only the desired region Id from the dataset
isolatedFilter = vtk.vtkPolyDataConnectivityFilter()
isolatedFilter.SetInputData(self.CurrentPickedPolyData)
isolatedFilter.SetExtractionModeToSpecifiedRegions()
isolatedFilter.AddSpecifiedRegion(regionId)
# remove all points not in the extracted cells
cleanedFilter = vtk.vtkCleanPolyData()
cleanedFilter.SetInputConnection(isolatedFilter.GetOutputPort())
cleanedFilter.Update()
outputSurface = cleanedFilter.GetOutput()
# create a new mapper and actor for this extracted surface object
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(outputSurface)
mapper.ScalarVisibilityOff()
mapper.Update()
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().SetColor(1.0, 0.0, 0.0) # red color
actor.GetProperty().SetDiffuse(1.0)
actor.GetProperty().SetSpecular(0.2)
actor.GetProperty().SetRepresentationToSurface()
actor.GetProperty().EdgeVisibilityOff()
# place the extracted surface object's actor instance in the necessary render windows
# and lists to log it's selection
self.PastPickedActorList.append(actor)
self._OutputPolyDataList.append(outputSurface)
self.vmtkRenderer.Renderer.AddActor(actor)
self.vmtkRenderer.RenderWindow.Render()
return
def Execute(self):
if not self.vmtkRenderer:
self.vmtkRenderer = vmtkrenderer.vmtkRenderer()
self.vmtkRenderer.Initialize()
self.OwnRenderer = 1
self.vmtkRenderer.RegisterScript(self.Script)
self.vmtkRenderer.AddKeyBinding('u','Undo.',self.UndoCallback)
self.vmtkRenderer.AddKeyBinding('space','Add points.',self.PickCallback)
self.InputInfo('Please position the mouse and press space to add target points, \'u\' to undo\n')
# this is necessary to set up the async watch loop.
any = 0
while any == 0:
self.vmtkRenderer.Render()
try:
any = self.CurrentPickedPolyData
except AttributeError:
any = None
if self.OwnRenderer:
self.vmtkRenderer.Deallocate()
class vmtkSurfaceConnectivitySelector(pypes.pypeScript):
def __init__(self):
pypes.pypeScript.__init__(self)
self.SeedSelector = None
self.Surface = None
self.vmtkRenderer = None
self.OwnRenderer = 0
self.OutputSeedIds = []
self.SetScriptName('vmtksurfaceconnectivityselector')
self.SetScriptDoc('interactively select the desired surfaces from a dataset composed of disconnected components')
self.SetInputMembers([
['Surface','i','vtkPolyData',1,'','the input surface','vmtksurfacereader'],
['vmtkRenderer','renderer','vmtkRenderer',1,'','external renderer']])
self.SetOutputMembers([
['Surface','o','vtkPolyData',1,'','the output surface','vmtksurfacewriter']])
def Execute(self):
if self.Surface == None:
self.PrintError('Error: No input surface.')
if not self.vmtkRenderer:
self.vmtkRenderer = vmtkrenderer.vmtkRenderer()
self.vmtkRenderer.Initialize()
self.OwnRenderer = 1
self.vmtkRenderer.RegisterScript(self)
# a check to make sure nothing has ran out of order.
if self.SeedSelector:
pass
else:
# initialize the seed selection method
self.SeedSelector = vmtkPickPointSeedSelector()
self.SeedSelector.vmtkRenderer = self.vmtkRenderer
self.SeedSelector.Script = self
# label all non-connected regions in an input surface.
allRegionConnectivity = vtk.vtkPolyDataConnectivityFilter()
allRegionConnectivity.SetInputData(self.Surface)
allRegionConnectivity.SetExtractionModeToAllRegions()
allRegionConnectivity.ColorRegionsOn()
allRegionConnectivity.Update()
# create the actor/mapper which renders the labeled input surface
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputData(allRegionConnectivity.GetOutput())
mapper.ScalarVisibilityOff()
mapper.Update()
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().SetColor(0.7, 0.7, 0.7) # standard gray color
actor.GetProperty().SetDiffuse(0.9)
actor.GetProperty().SetSpecular(0.2)
actor.GetProperty().SetRepresentationToSurface()
actor.GetProperty().EdgeVisibilityOff()
# add this as the main actor to the scene (the first think you see)
self.vmtkRenderer.Renderer.AddActor(actor)
if self.SeedSelector:
self.SeedSelector.InputInfo = self.InputInfo
self.SeedSelector.InputText = self.InputText
self.SeedSelector.OutputText = self.OutputText
self.SeedSelector.PrintError = self.PrintError
self.SeedSelector.PrintLog = self.PrintLog
# until SeedSelector releases control of execution, the program will not
# proceed past the next line. SeedSelector handles all user interaction and
# modification/logging of actor properties & region Ids
self.SeedSelector.Execute()
# we store each extracted region as individual vtkPolyData objects within a list.
# They are combined into one dataset below.
polyDataAppender = vtk.vtkAppendPolyData()
for outputSurfacePolyData in self.SeedSelector._OutputPolyDataList:
polyDataAppender.AddInputData(outputSurfacePolyData)
# Even though we clean the selection in the SeedSelection, this is necessary because it
# may be possible for a user to select the same polydata object twice. If this is not cleaned,
# a double selection may mess with further post processing scripts.
polyDataCleaner = vtk.vtkCleanPolyData()
polyDataCleaner.SetInputConnection(polyDataAppender.GetOutputPort())
polyDataCleaner.Update()
self.Surface = polyDataAppender.GetOutput()
if self.OwnRenderer:
self.vmtkRenderer.Deallocate()
if __name__ == '__main__':
main = pypes.pypeMain()
main.Arguments = sys.argv
main.Execute()