Commit f5d0049f3c1f7c22f6839fa0a54443fc83b8618c

Authored by Paulo Henrique Junqueira Amorim
1 parent 2fb6b86d

FIX: Error generate 3D surface FIX #98

.gitattributes
... ... @@ -116,6 +116,7 @@ invesalius/data/slice_.py -text
116 116 invesalius/data/slice_data.py -text
117 117 invesalius/data/styles.py -text
118 118 invesalius/data/surface.py -text
  119 +invesalius/data/surface_process.py -text
119 120 invesalius/data/viewer.py -text
120 121 invesalius/data/viewer_slice.py -text
121 122 invesalius/data/viewer_volume.py -text
... ...
invesalius/data/surface.py
... ... @@ -31,110 +31,9 @@ import imagedata_utils as iu
31 31 import polydata_utils as pu
32 32 import project as prj
33 33 import session as ses
  34 +import surface_process
34 35 import vtk_utils as vu
35 36  
36   -#------------------------------------------------------------------
37   -class SurfaceProcess(multiprocessing.Process):
38   -
39   - def __init__(self, pipe, filename, mode, min_value, max_value,
40   - decimate_reduction, smooth_relaxation_factor,
41   - smooth_iterations):
42   -
43   - multiprocessing.Process.__init__(self)
44   - self.pipe = pipe
45   - self.filename = filename
46   - self.mode = mode
47   - self.min_value = min_value
48   - self.max_value = max_value
49   - self.decimate_reduction = decimate_reduction
50   - self.smooth_relaxation_factor = smooth_relaxation_factor
51   - self.smooth_iterations = smooth_iterations
52   -
53   - def run(self):
54   - self.CreateSurface()
55   -
56   - def SendProgress(self, obj, msg):
57   - prog = obj.GetProgress()
58   - self.pipe.send([prog, msg])
59   -
60   - def CreateSurface(self):
61   -
62   - reader = vtk.vtkXMLImageDataReader()
63   - reader.SetFileName(self.filename)
64   - reader.Update()
65   -
66   - # Flip original vtkImageData
67   - flip = vtk.vtkImageFlip()
68   - flip.SetInput(reader.GetOutput())
69   - flip.SetFilteredAxis(1)
70   - flip.FlipAboutOriginOn()
71   -
72   - # Create vtkPolyData from vtkImageData
73   - if self.mode == "CONTOUR":
74   - contour = vtk.vtkContourFilter()
75   - contour.SetInput(flip.GetOutput())
76   - contour.SetValue(0, self.min_value) # initial threshold
77   - contour.SetValue(1, self.max_value) # final threshold
78   - contour.GetOutput().ReleaseDataFlagOn()
79   - contour.AddObserver("ProgressEvent", lambda obj,evt:
80   - self.SendProgress(obj, "Generating 3D surface..."))
81   - polydata = contour.GetOutput()
82   - else: #mode == "GRAYSCALE":
83   - mcubes = vtk.vtkMarchingCubes()
84   - mcubes.SetInput(flip.GetOutput())
85   - mcubes.SetValue(0, 255)
86   - mcubes.ComputeScalarsOn()
87   - mcubes.ComputeGradientsOn()
88   - mcubes.ComputeNormalsOn()
89   - mcubes.ThresholdBetween(self.min_value, self.max_value)
90   - mcubes.GetOutput().ReleaseDataFlagOn()
91   - mcubes.AddObserver("ProgressEvent", lambda obj,evt:
92   - self.SendProgress(obj, "Generating 3D surface..."))
93   - polydata = mcubes.GetOutput()
94   -
95   - if self.decimate_reduction:
96   - decimation = vtk.vtkQuadricDecimation()
97   - decimation.SetInput(polydata)
98   - decimation.SetTargetReduction(self.decimate_reduction)
99   - decimation.GetOutput().ReleaseDataFlagOn()
100   - decimation.AddObserver("ProgressEvent", lambda obj,evt:
101   - self.SendProgress(obj, "Generating 3D surface..."))
102   - polydata = decimation.GetOutput()
103   -
104   - if self.smooth_iterations and self.smooth_relaxation_factor:
105   - smoother = vtk.vtkSmoothPolyDataFilter()
106   - smoother.SetInput(polydata)
107   - smoother.SetNumberOfIterations(self.smooth_iterations)
108   - smoother.SetFeatureAngle(80)
109   - smoother.SetRelaxationFactor(self.smooth_relaxation_factor)
110   - smoother.FeatureEdgeSmoothingOn()
111   - smoother.BoundarySmoothingOn()
112   - smoother.GetOutput().ReleaseDataFlagOn()
113   - smoother.AddObserver("ProgressEvent", lambda obj,evt:
114   - self.SendProgress(obj, "Generating 3D surface..."))
115   - polydata = smoother.GetOutput()
116   -
117   - # Filter used to detect and fill holes. Only fill boundary edges holes.
118   - #TODO: Hey! This piece of code is the same from
119   - # polydata_utils.FillSurfaceHole, we need to review this.
120   - filled_polydata = vtk.vtkFillHolesFilter()
121   - filled_polydata.SetInput(polydata)
122   - filled_polydata.SetHoleSize(500)
123   - filled_polydata.AddObserver("ProgressEvent", lambda obj,evt:
124   - self.SendProgress(obj, "Generating 3D surface..."))
125   - polydata = filled_polydata.GetOutput()
126   -
127   -
128   - filename = tempfile.mktemp()
129   - writer = vtk.vtkXMLPolyDataWriter()
130   - writer.SetInput(polydata)
131   - writer.SetFileName(filename)
132   - writer.Write()
133   -
134   - self.pipe.send(None)
135   - self.pipe.send(filename)
136   -
137   -#----------------------------------------------------------------------------------------------
138 37 class Surface():
139 38 """
140 39 Represent both vtkPolyData and associated properties.
... ... @@ -161,8 +60,8 @@ class Surface():
161 60 surface[key] = {'$vtp': os.path.split(img_name)[1]}
162 61 else:
163 62 surface[key] = d[key]
164   -
165   -
  63 +
  64 +
166 65 plistlib.writePlist(surface, filename + '.plist')
167 66 return os.path.split(filename)[1] + '.plist'
168 67  
... ... @@ -225,18 +124,18 @@ class SurfaceManager():
225 124 for key in surface_dict:
226 125 surface = surface_dict[key]
227 126 # Map polygonal data (vtkPolyData) to graphics primitives.
228   -
  127 +
229 128 normals = vtk.vtkPolyDataNormals()
230 129 normals.SetInput(surface.polydata)
231 130 normals.SetFeatureAngle(80)
232 131 normals.AutoOrientNormalsOn()
233 132 normals.GetOutput().ReleaseDataFlagOn()
234   -
  133 +
235 134 stripper = vtk.vtkStripper()
236 135 stripper.SetInput(normals.GetOutput())
237 136 stripper.PassThroughCellIdsOn()
238 137 stripper.PassThroughPointIdsOn()
239   -
  138 +
240 139 mapper = vtk.vtkPolyDataMapper()
241 140 mapper.SetInput(stripper.GetOutput())
242 141 mapper.ScalarVisibilityOff()
... ... @@ -257,7 +156,7 @@ class SurfaceManager():
257 156  
258 157 ps.Publisher().sendMessage('Update status text in GUI',
259 158 "Surface created.")
260   -
  159 +
261 160 # The following lines have to be here, otherwise all volumes disappear
262 161  
263 162 ps.Publisher().sendMessage('Update surface info in GUI',
... ... @@ -275,7 +174,7 @@ class SurfaceManager():
275 174 imagedata, colour, [min_value, max_value], edited_points = pubsub_evt.data
276 175 quality=_('Optimal *')
277 176 mode = 'CONTOUR' # 'GRAYSCALE'
278   -
  177 +
279 178 imagedata_tmp = None
280 179 if (edited_points):
281 180 imagedata_tmp = vtk.vtkImageData()
... ... @@ -299,49 +198,51 @@ class SurfaceManager():
299 198 pipeline_size += 1
300 199  
301 200 # Update progress value in GUI
302   -
  201 +
303 202 filename_img = tempfile.mktemp()
304   -
  203 +
305 204 writer = vtk.vtkXMLImageDataWriter()
306 205 writer.SetFileName(filename_img)
307 206 writer.SetInput(imagedata)
308 207 writer.Write()
309   -
  208 +
310 209 #pipeline_size = 4
311 210 UpdateProgress = vu.ShowProgress(pipeline_size)
312   -
  211 +
  212 + language = ses.Session().language
  213 +
313 214 pipe_in, pipe_out = multiprocessing.Pipe()
314   - sp = SurfaceProcess(pipe_in, filename_img, mode, min_value, max_value,
315   - decimate_reduction, smooth_relaxation_factor,
316   - smooth_iterations)
  215 + sp = surface_process.SurfaceProcess(pipe_in, filename_img, mode, min_value, max_value,
  216 + decimate_reduction, smooth_relaxation_factor,
  217 + smooth_iterations, language)
317 218 sp.start()
318   -
  219 +
319 220 while 1:
320 221 msg = pipe_out.recv()
321 222 if(msg is None):
322 223 break
323 224 UpdateProgress(msg[0],msg[1])
324   -
  225 +
325 226 filename_polydata = pipe_out.recv()
326   -
  227 +
327 228 reader = vtk.vtkXMLPolyDataReader()
328 229 reader.SetFileName(filename_polydata)
329 230 reader.Update()
330   -
  231 +
331 232 polydata = reader.GetOutput()
332   -
  233 +
333 234 # Orient normals from inside to outside
334 235 normals = vtk.vtkPolyDataNormals()
335 236 normals.SetInput(polydata)
336 237 normals.SetFeatureAngle(80)
337 238 normals.AutoOrientNormalsOn()
338 239 normals.GetOutput().ReleaseDataFlagOn()
339   -
  240 +
340 241 stripper = vtk.vtkStripper()
341 242 stripper.SetInput(normals.GetOutput())
342 243 stripper.PassThroughCellIdsOn()
343 244 stripper.PassThroughPointIdsOn()
344   -
  245 +
345 246 # Map polygonal data (vtkPolyData) to graphics primitives.
346 247 mapper = vtk.vtkPolyDataMapper()
347 248 mapper.SetInput(stripper.GetOutput())
... ... @@ -360,8 +261,8 @@ class SurfaceManager():
360 261 # Set actor colour and transparency
361 262 actor.GetProperty().SetColor(colour)
362 263 actor.GetProperty().SetOpacity(1-surface.transparency)
363   -
364   - # Remove temporary files
  264 +
  265 + # Remove temporary files
365 266 if sys.platform == "win32":
366 267 try:
367 268 os.remove(filename_img)
... ... @@ -371,7 +272,7 @@ class SurfaceManager():
371 272 else:
372 273 os.remove(filename_img)
373 274 os.remove(filename_polydata)
374   -
  275 +
375 276 # Append surface into Project.surface_dict
376 277 proj = prj.Project()
377 278 index = proj.AddSurface(surface)
... ... @@ -494,12 +395,12 @@ class SurfaceManager():
494 395 writer = vtk.vtkXMLPolyDataWriter()
495 396 #elif filetype == const.FILETYPE_IV:
496 397 # writer = vtk.vtkIVWriter()
497   - elif filetype == const.FILETYPE_PLY:
  398 + elif filetype == const.FILETYPE_PLY:
498 399 writer = vtk.vtkPLYWriter()
499 400 writer.SetFileTypeToBinary()
500 401 writer.SetDataByteOrderToLittleEndian()
501 402 #writer.SetColorModeToUniformCellColor()
502   - #writer.SetColor(255, 0, 0)
  403 + #writer.SetColor(255, 0, 0)
503 404  
504 405 if filetype == const.FILETYPE_STL:
505 406 # Invert normals
... ... @@ -508,7 +409,7 @@ class SurfaceManager():
508 409 normals.SetFeatureAngle(80)
509 410 normals.AutoOrientNormalsOn()
510 411 normals.GetOutput().ReleaseDataFlagOn()
511   - normals.UpdateInformation()
  412 + normals.UpdateInformation()
512 413 polydata = normals.GetOutput()
513 414  
514 415 writer.SetFileName(filename)
... ...
invesalius/data/surface_process.py 0 → 100644
... ... @@ -0,0 +1,107 @@
  1 +import vtk
  2 +import multiprocessing
  3 +import tempfile
  4 +
  5 +import i18n
  6 +
  7 +class SurfaceProcess(multiprocessing.Process):
  8 +
  9 + def __init__(self, pipe, filename, mode, min_value, max_value,
  10 + decimate_reduction, smooth_relaxation_factor,
  11 + smooth_iterations, language):
  12 +
  13 + multiprocessing.Process.__init__(self)
  14 + self.pipe = pipe
  15 + self.filename = filename
  16 + self.mode = mode
  17 + self.min_value = min_value
  18 + self.max_value = max_value
  19 + self.decimate_reduction = decimate_reduction
  20 + self.smooth_relaxation_factor = smooth_relaxation_factor
  21 + self.smooth_iterations = smooth_iterations
  22 + _ = i18n.InstallLanguage(language)
  23 +
  24 +
  25 + def run(self):
  26 + self.CreateSurface()
  27 +
  28 + def SendProgress(self, obj, msg):
  29 + prog = obj.GetProgress()
  30 + self.pipe.send([prog, msg])
  31 +
  32 + def CreateSurface(self):
  33 +
  34 + reader = vtk.vtkXMLImageDataReader()
  35 + reader.SetFileName(self.filename)
  36 + reader.Update()
  37 +
  38 + # Flip original vtkImageData
  39 + flip = vtk.vtkImageFlip()
  40 + flip.SetInput(reader.GetOutput())
  41 + flip.SetFilteredAxis(1)
  42 + flip.FlipAboutOriginOn()
  43 +
  44 + # Create vtkPolyData from vtkImageData
  45 + if self.mode == "CONTOUR":
  46 + contour = vtk.vtkContourFilter()
  47 + contour.SetInput(flip.GetOutput())
  48 + contour.SetValue(0, self.min_value) # initial threshold
  49 + contour.SetValue(1, self.max_value) # final threshold
  50 + contour.GetOutput().ReleaseDataFlagOn()
  51 + contour.AddObserver("ProgressEvent", lambda obj,evt:
  52 + self.SendProgress(obj, _("Generating 3D surface...")))
  53 + polydata = contour.GetOutput()
  54 + else: #mode == "GRAYSCALE":
  55 + mcubes = vtk.vtkMarchingCubes()
  56 + mcubes.SetInput(flip.GetOutput())
  57 + mcubes.SetValue(0, 255)
  58 + mcubes.ComputeScalarsOn()
  59 + mcubes.ComputeGradientsOn()
  60 + mcubes.ComputeNormalsOn()
  61 + mcubes.ThresholdBetween(self.min_value, self.max_value)
  62 + mcubes.GetOutput().ReleaseDataFlagOn()
  63 + mcubes.AddObserver("ProgressEvent", lambda obj,evt:
  64 + self.SendProgress(obj, _("Generating 3D surface...")))
  65 + polydata = mcubes.GetOutput()
  66 +
  67 + if self.decimate_reduction:
  68 + decimation = vtk.vtkQuadricDecimation()
  69 + decimation.SetInput(polydata)
  70 + decimation.SetTargetReduction(self.decimate_reduction)
  71 + decimation.GetOutput().ReleaseDataFlagOn()
  72 + decimation.AddObserver("ProgressEvent", lambda obj,evt:
  73 + self.SendProgress(obj, _("Generating 3D surface...")))
  74 + polydata = decimation.GetOutput()
  75 +
  76 + if self.smooth_iterations and self.smooth_relaxation_factor:
  77 + smoother = vtk.vtkSmoothPolyDataFilter()
  78 + smoother.SetInput(polydata)
  79 + smoother.SetNumberOfIterations(self.smooth_iterations)
  80 + smoother.SetFeatureAngle(80)
  81 + smoother.SetRelaxationFactor(self.smooth_relaxation_factor)
  82 + smoother.FeatureEdgeSmoothingOn()
  83 + smoother.BoundarySmoothingOn()
  84 + smoother.GetOutput().ReleaseDataFlagOn()
  85 + smoother.AddObserver("ProgressEvent", lambda obj,evt:
  86 + self.SendProgress(obj, _("Generating 3D surface...")))
  87 + polydata = smoother.GetOutput()
  88 +
  89 + # Filter used to detect and fill holes. Only fill boundary edges holes.
  90 + #TODO: Hey! This piece of code is the same from
  91 + # polydata_utils.FillSurfaceHole, we need to review this.
  92 + filled_polydata = vtk.vtkFillHolesFilter()
  93 + filled_polydata.SetInput(polydata)
  94 + filled_polydata.SetHoleSize(500)
  95 + filled_polydata.AddObserver("ProgressEvent", lambda obj,evt:
  96 + self.SendProgress(obj, _("Generating 3D surface...")))
  97 + polydata = filled_polydata.GetOutput()
  98 +
  99 +
  100 + filename = tempfile.mktemp()
  101 + writer = vtk.vtkXMLPolyDataWriter()
  102 + writer.SetInput(polydata)
  103 + writer.SetFileName(filename)
  104 + writer.Write()
  105 +
  106 + self.pipe.send(None)
  107 + self.pipe.send(filename)
0 108 \ No newline at end of file
... ...