Commit a724a203ef29718751ee50e146b33b2b9accc8ab

Authored by tfmoraes
1 parent a3614eda

ENH: Generating surface using multiprocessing and with memmap

invesalius/data/imagedata_utils.py
@@ -497,20 +497,23 @@ def dcm2memmap(files, slice_size, orientation): @@ -497,20 +497,23 @@ def dcm2memmap(files, slice_size, orientation):
497 return matrix, temp_file 497 return matrix, temp_file
498 498
499 def to_vtk(n_array, spacing, slice_number, orientation): 499 def to_vtk(n_array, spacing, slice_number, orientation):
500 - dy, dx = n_array.shape 500 + try:
  501 + dz, dy, dx = n_array.shape
  502 + except ValueError:
  503 + dy, dx = n_array.shape
  504 + dz = 1
501 505
502 v_image = numpy_support.numpy_to_vtk(n_array.flat) 506 v_image = numpy_support.numpy_to_vtk(n_array.flat)
503 507
504 print orientation 508 print orientation
505 if orientation == 'AXIAL': 509 if orientation == 'AXIAL':
506 - dz = 1  
507 - extent = (0, dx -1, 0, dy -1, slice_number, slice_number) 510 + extent = (0, dx -1, 0, dy -1, slice_number, slice_number + dz - 1)
508 elif orientation == 'SAGITAL': 511 elif orientation == 'SAGITAL':
509 - dx, dy, dz = 1, dx, dy  
510 - extent = (slice_number, slice_number, 0, dy - 1, 0, dz - 1) 512 + dx, dy, dz = dz, dx, dy
  513 + extent = (slice_number, slice_number + dx - 1, 0, dy - 1, 0, dz - 1)
511 elif orientation == 'CORONAL': 514 elif orientation == 'CORONAL':
512 - dx, dy, dz = dx, 1, dy  
513 - extent = (0, dx - 1, slice_number, slice_number, 0, dz - 1) 515 + dx, dy, dz = dx, dz, dy
  516 + extent = (0, dx - 1, slice_number, slice_number + dy - 1, 0, dz - 1)
514 517
515 # Generating the vtkImageData 518 # Generating the vtkImageData
516 image = vtk.vtkImageData() 519 image = vtk.vtkImageData()
invesalius/data/slice_.py
@@ -260,8 +260,8 @@ class Slice(object): @@ -260,8 +260,8 @@ class Slice(object):
260 #--------------------------------------------------------------------------- 260 #---------------------------------------------------------------------------
261 261
262 def GetSlices(self, orientation, slice_number): 262 def GetSlices(self, orientation, slice_number):
263 - print "Getting slice", self.buffer_slices[orientation][0], slice_number  
264 if self.buffer_slices[orientation][0] == slice_number: 263 if self.buffer_slices[orientation][0] == slice_number:
  264 + print "From buffer"
265 image = self.buffer_slices[orientation][1] 265 image = self.buffer_slices[orientation][1]
266 if self.current_mask and self.current_mask.is_shown: 266 if self.current_mask and self.current_mask.is_shown:
267 n_mask = self.buffer_slices[orientation][2] 267 n_mask = self.buffer_slices[orientation][2]
@@ -275,7 +275,6 @@ class Slice(object): @@ -275,7 +275,6 @@ class Slice(object):
275 image = self.do_ww_wl(image) 275 image = self.do_ww_wl(image)
276 276
277 if self.current_mask and self.current_mask.is_shown: 277 if self.current_mask and self.current_mask.is_shown:
278 - print "Mask"  
279 n_mask = self.GetMaskSlice(orientation, slice_number) 278 n_mask = self.GetMaskSlice(orientation, slice_number)
280 mask = iu.to_vtk(n_mask, self.spacing, slice_number, orientation) 279 mask = iu.to_vtk(n_mask, self.spacing, slice_number, orientation)
281 final_image = self.do_blend(image, self.do_colour_mask(mask)) 280 final_image = self.do_blend(image, self.do_colour_mask(mask))
@@ -411,12 +410,12 @@ class Slice(object): @@ -411,12 +410,12 @@ class Slice(object):
411 m[slice_ < thresh_min] = 0 410 m[slice_ < thresh_min] = 0
412 m[slice_ > thresh_max] = 0 411 m[slice_ > thresh_max] = 0
413 m[m == 1] = 255 412 m[m == 1] = 255
414 - self.current_mask.matrix[n] = m 413 + self.current_mask.matrix[n+1, 1:, 1:] = m
415 else: 414 else:
416 print "Only one slice" 415 print "Only one slice"
417 slice_ = self.buffer_slices[orientation][3] 416 slice_ = self.buffer_slices[orientation][3]
418 - self.buffer_slices[orientation][2][:] = 0  
419 - self.buffer_slices[orientation][2][numpy.logical_and(slice_ >= thresh_min,slice_ <= thresh_max)] = 255 417 + self.buffer_slices[orientation][2] = 255 * ((slice_ >= thresh_min) & (slice_ <= thresh_max))
  418 + print self.buffer_slices[orientation][2].dtype
420 419
421 # Update viewer 420 # Update viewer
422 #ps.Publisher().sendMessage('Update slice viewer') 421 #ps.Publisher().sendMessage('Update slice viewer')
@@ -521,15 +520,15 @@ class Slice(object): @@ -521,15 +520,15 @@ class Slice(object):
521 520
522 # This is very important. Do not use masks' imagedata. It would mess up 521 # This is very important. Do not use masks' imagedata. It would mess up
523 # surface quality event when using contour 522 # surface quality event when using contour
524 - imagedata = self.imagedata  
525 -  
526 colour = mask.colour 523 colour = mask.colour
527 threshold = mask.threshold_range 524 threshold = mask.threshold_range
528 edited_points = mask.edited_points 525 edited_points = mask.edited_points
529 526
530 - ps.Publisher().sendMessage('Create surface',  
531 - (imagedata,colour,threshold,  
532 - edited_points, overwrite_surface)) 527 + self.SetMaskThreshold(mask.index, threshold)
  528 +
  529 + mask.matrix.flush()
  530 +
  531 + ps.Publisher().sendMessage('Create surface', (mask, self.spacing))
533 532
534 def GetOutput(self): 533 def GetOutput(self):
535 return self.blend_filter.GetOutput() 534 return self.blend_filter.GetOutput()
invesalius/data/surface.py
@@ -376,29 +376,36 @@ class SurfaceManager(): @@ -376,29 +376,36 @@ class SurfaceManager():
376 Create surface actor, save into project and send it to viewer. 376 Create surface actor, save into project and send it to viewer.
377 """ 377 """
378 surface_data = pubsub_evt.data 378 surface_data = pubsub_evt.data
379 -  
380 - if len(surface_data) == 5:  
381 - imagedata, colour, [min_value, max_value], \  
382 - edited_points, overwrite = pubsub_evt.data  
383 - quality=_('Optimal *')  
384 - surface_name = ""  
385 - fill_holes = True  
386 - keep_largest = False  
387 - else:  
388 - imagedata, colour, [min_value, max_value],\  
389 - edited_points, overwrite, surface_name,\  
390 - quality, fill_holes, keep_largest =\  
391 - pubsub_evt.data 379 + mask, spacing = pubsub_evt.data
  380 + min_value, max_value = mask.threshold_range
  381 + fill_holes = True
  382 +
  383 + #if len(surface_data) == 5:
  384 + #imagedata, colour, [min_value, max_value], \
  385 + #edited_points, overwrite = pubsub_evt.data
  386 + #quality=_('Optimal *')
  387 + #surface_name = ""
  388 + #fill_holes = True
  389 + #keep_largest = False
  390 + #else:
  391 + #imagedata, colour, [min_value, max_value],\
  392 + #edited_points, overwrite, surface_name,\
  393 + #quality, fill_holes, keep_largest =\
  394 + #pubsub_evt.data
392 395
393 mode = 'CONTOUR' # 'GRAYSCALE' 396 mode = 'CONTOUR' # 'GRAYSCALE'
394 -  
395 - ps.Publisher().sendMessage('Begin busy cursor')  
396 - imagedata_tmp = None  
397 - if (edited_points):  
398 - imagedata_tmp = vtk.vtkImageData()  
399 - imagedata_tmp.DeepCopy(imagedata)  
400 - imagedata_tmp.Update()  
401 - imagedata = iu.BuildEditedImage(imagedata_tmp, edited_points) 397 + quality=_('Optimal *')
  398 + keep_largest = True
  399 + surface_name = ""
  400 + colour = mask.colour
  401 +
  402 + #ps.Publisher().sendMessage('Begin busy cursor')
  403 + #imagedata_tmp = None
  404 + #if (edited_points):
  405 + #imagedata_tmp = vtk.vtkImageData()
  406 + #imagedata_tmp.DeepCopy(imagedata)
  407 + #imagedata_tmp.Update()
  408 + #imagedata = iu.BuildEditedImage(imagedata_tmp, edited_points)
402 409
403 if quality in const.SURFACE_QUALITY.keys(): 410 if quality in const.SURFACE_QUALITY.keys():
404 imagedata_resolution = const.SURFACE_QUALITY[quality][0] 411 imagedata_resolution = const.SURFACE_QUALITY[quality][0]
@@ -406,61 +413,89 @@ class SurfaceManager(): @@ -406,61 +413,89 @@ class SurfaceManager():
406 smooth_relaxation_factor = const.SURFACE_QUALITY[quality][2] 413 smooth_relaxation_factor = const.SURFACE_QUALITY[quality][2]
407 decimate_reduction = const.SURFACE_QUALITY[quality][3] 414 decimate_reduction = const.SURFACE_QUALITY[quality][3]
408 415
409 - if imagedata_resolution:  
410 - imagedata = iu.ResampleImage3D(imagedata, imagedata_resolution) 416 + #if imagedata_resolution:
  417 + #imagedata = iu.ResampleImage3D(imagedata, imagedata_resolution)
411 418
412 - pipeline_size = 4  
413 - if decimate_reduction:  
414 - pipeline_size += 1  
415 - if (smooth_iterations and smooth_relaxation_factor):  
416 - pipeline_size += 1  
417 - if fill_holes:  
418 - pipeline_size += 1  
419 - if keep_largest:  
420 - pipeline_size += 1 419 + #pipeline_size = 4
  420 + #if decimate_reduction:
  421 + #pipeline_size += 1
  422 + #if (smooth_iterations and smooth_relaxation_factor):
  423 + #pipeline_size += 1
  424 + #if fill_holes:
  425 + #pipeline_size += 1
  426 + #if keep_largest:
  427 + #pipeline_size += 1
421 428
422 - # Update progress value in GUI  
423 - UpdateProgress = vu.ShowProgress(pipeline_size)  
424 - UpdateProgress(0, _("Generating 3D surface...")) 429 + ## Update progress value in GUI
  430 + #UpdateProgress = vu.ShowProgress(pipeline_size)
  431 + #UpdateProgress(0, _("Generating 3D surface..."))
425 432
426 - filename_img = tempfile.mktemp() 433 + #filename_img = tempfile.mktemp()
427 434
428 - writer = vtk.vtkXMLImageDataWriter()  
429 - writer.SetFileName(filename_img)  
430 - writer.SetInput(imagedata)  
431 - writer.Write() 435 + #writer = vtk.vtkXMLImageDataWriter()
  436 + #writer.SetFileName(filename_img)
  437 + #writer.SetInput(imagedata)
  438 + #writer.Write()
432 439
433 language = ses.Session().language 440 language = ses.Session().language
  441 +
  442 + filename_img = mask.temp_file
  443 + overwrite = 0
434 444
435 if (prj.Project().original_orientation == const.CORONAL): 445 if (prj.Project().original_orientation == const.CORONAL):
436 flip_image = False 446 flip_image = False
437 else: 447 else:
438 flip_image = True 448 flip_image = True
  449 +
  450 + n_processors = 1 # multiprocessing.cpu_count()
439 451
440 pipe_in, pipe_out = multiprocessing.Pipe() 452 pipe_in, pipe_out = multiprocessing.Pipe()
441 - sp = surface_process.SurfaceProcess(pipe_in, filename_img, mode, min_value, max_value,  
442 - decimate_reduction, smooth_relaxation_factor,  
443 - smooth_iterations, language, fill_holes, keep_largest, flip_image)  
444 - sp.start()  
445 -  
446 - while 1:  
447 - msg = pipe_out.recv()  
448 - if(msg is None):  
449 - break  
450 - UpdateProgress(msg[0],msg[1])  
451 -  
452 - filename_polydata = pipe_out.recv()  
453 -  
454 - reader = vtk.vtkXMLPolyDataReader()  
455 - reader.SetFileName(filename_polydata)  
456 - reader.Update()  
457 -  
458 - polydata = reader.GetOutput() 453 + o_piece = 2
  454 + piece_size = 40
  455 +
  456 + n_pieces = round(mask.matrix.shape[0] / piece_size + 0.5, 0)
  457 + print "n_pieces", n_pieces, mask.matrix.shape
  458 +
  459 + q_in = multiprocessing.Queue()
  460 + q_out = multiprocessing.Queue()
  461 +
  462 + p = []
  463 + for i in xrange(n_processors):
  464 + sp = surface_process.SurfaceProcess(pipe_in, filename_img,
  465 + mask.matrix.shape, mask.matrix.dtype, spacing,
  466 + mode, min_value, max_value,
  467 + decimate_reduction, smooth_relaxation_factor,
  468 + smooth_iterations, language, fill_holes, keep_largest,
  469 + flip_image, q_in, q_out)
  470 + p.append(sp)
  471 + sp.start()
  472 +
  473 + for i in xrange(n_pieces):
  474 + init = i * piece_size
  475 + end = init + piece_size + o_piece
  476 + roi = slice(init, end)
  477 + q_in.put(roi)
  478 + print "new_piece", roi
  479 +
  480 + for i in p:
  481 + q_in.put(None)
  482 +
  483 + polydata_append = vtk.vtkAppendPolyData()
  484 + t = n_pieces
  485 + while t:
  486 + filename_polydata = q_out.get()
  487 +
  488 + reader = vtk.vtkXMLPolyDataReader()
  489 + reader.SetFileName(filename_polydata)
  490 + reader.Update()
  491 + polydata_append.AddInput(reader.GetOutput())
  492 +
  493 + t -= 1
  494 +
  495 + polydata = polydata_append.GetOutput()
459 496
460 # Orient normals from inside to outside 497 # Orient normals from inside to outside
461 normals = vtk.vtkPolyDataNormals() 498 normals = vtk.vtkPolyDataNormals()
462 - normals.AddObserver("ProgressEvent", lambda obj,evt:  
463 - UpdateProgress(obj, _("Generating 3D surface...")))  
464 normals.SetInput(polydata) 499 normals.SetInput(polydata)
465 normals.SetFeatureAngle(80) 500 normals.SetFeatureAngle(80)
466 normals.AutoOrientNormalsOn() 501 normals.AutoOrientNormalsOn()
@@ -468,8 +503,6 @@ class SurfaceManager(): @@ -468,8 +503,6 @@ class SurfaceManager():
468 503
469 # Improve performance 504 # Improve performance
470 stripper = vtk.vtkStripper() 505 stripper = vtk.vtkStripper()
471 - stripper.AddObserver("ProgressEvent", lambda obj,evt:  
472 - UpdateProgress(obj, _("Generating 3D surface...")))  
473 stripper.SetInput(normals.GetOutput()) 506 stripper.SetInput(normals.GetOutput())
474 stripper.PassThroughCellIdsOn() 507 stripper.PassThroughCellIdsOn()
475 stripper.PassThroughPointIdsOn() 508 stripper.PassThroughPointIdsOn()
@@ -526,8 +559,6 @@ class SurfaceManager(): @@ -526,8 +559,6 @@ class SurfaceManager():
526 559
527 # The following lines have to be here, otherwise all volumes disappear 560 # The following lines have to be here, otherwise all volumes disappear
528 measured_polydata = vtk.vtkMassProperties() 561 measured_polydata = vtk.vtkMassProperties()
529 - measured_polydata.AddObserver("ProgressEvent", lambda obj,evt:  
530 - UpdateProgress(obj, _("Generating 3D surface...")))  
531 measured_polydata.SetInput(polydata) 562 measured_polydata.SetInput(polydata)
532 volume = measured_polydata.GetVolume() 563 volume = measured_polydata.GetVolume()
533 surface.volume = volume 564 surface.volume = volume
@@ -552,10 +583,6 @@ class SurfaceManager(): @@ -552,10 +583,6 @@ class SurfaceManager():
552 surface.colour, surface.volume, 583 surface.colour, surface.volume,
553 surface.transparency)) 584 surface.transparency))
554 585
555 - #Destroy Copy original imagedata  
556 - if(imagedata_tmp):  
557 - del imagedata_tmp  
558 -  
559 ps.Publisher().sendMessage('End busy cursor') 586 ps.Publisher().sendMessage('End busy cursor')
560 587
561 def RemoveActor(self, index): 588 def RemoveActor(self, index):
invesalius/data/surface_process.py
1 -import vtk  
2 import multiprocessing 1 import multiprocessing
3 import tempfile 2 import tempfile
  3 +import time
  4 +
  5 +import numpy
  6 +import vtk
4 7
5 import i18n 8 import i18n
  9 +import imagedata_utils
  10 +
  11 +from scipy import ndimage
6 12
7 class SurfaceProcess(multiprocessing.Process): 13 class SurfaceProcess(multiprocessing.Process):
8 14
9 - def __init__(self, pipe, filename, mode, min_value, max_value, 15 + def __init__(self, pipe, filename, shape, dtype, spacing, mode, min_value, max_value,
10 decimate_reduction, smooth_relaxation_factor, 16 decimate_reduction, smooth_relaxation_factor,
11 smooth_iterations, language, fill_holes, keep_largest, 17 smooth_iterations, language, fill_holes, keep_largest,
12 - flip_image): 18 + flip_image, q_in, q_out):
13 19
14 multiprocessing.Process.__init__(self) 20 multiprocessing.Process.__init__(self)
15 self.pipe = pipe 21 self.pipe = pipe
  22 + self.spacing = spacing
16 self.filename = filename 23 self.filename = filename
17 self.mode = mode 24 self.mode = mode
18 self.min_value = min_value 25 self.min_value = min_value
@@ -24,64 +31,59 @@ class SurfaceProcess(multiprocessing.Process): @@ -24,64 +31,59 @@ class SurfaceProcess(multiprocessing.Process):
24 self.fill_holes = fill_holes 31 self.fill_holes = fill_holes
25 self.keep_largest = keep_largest 32 self.keep_largest = keep_largest
26 self.flip_image = flip_image 33 self.flip_image = flip_image
  34 + self.q_in = q_in
  35 + self.q_out = q_out
27 36
  37 + self.mask = numpy.memmap(filename, mode='r', dtype=dtype,
  38 + shape=shape)
28 39
29 def run(self): 40 def run(self):
30 - self.CreateSurface() 41 + while 1:
  42 + roi = self.q_in.get()
  43 + print roi
  44 + if roi is None:
  45 + break
  46 + self.CreateSurface(roi)
31 47
32 def SendProgress(self, obj, msg): 48 def SendProgress(self, obj, msg):
33 prog = obj.GetProgress() 49 prog = obj.GetProgress()
34 self.pipe.send([prog, msg]) 50 self.pipe.send([prog, msg])
35 51
36 - def CreateSurface(self):  
37 - _ = i18n.InstallLanguage(self.language)  
38 -  
39 - reader = vtk.vtkXMLImageDataReader()  
40 - reader.SetFileName(self.filename)  
41 - reader.Update()  
42 -  
43 - image = reader.GetOutput()  
44 -  
45 - if (self.flip_image):  
46 - # Flip original vtkImageData  
47 - flip = vtk.vtkImageFlip()  
48 - flip.SetInput(reader.GetOutput())  
49 - flip.SetFilteredAxis(1)  
50 - flip.FlipAboutOriginOn()  
51 - image = flip.GetOutput()  
52 - 52 + def CreateSurface(self, roi):
  53 + smoothed = ndimage.gaussian_filter(self.mask[roi], (1, 1, 1))
  54 + image = imagedata_utils.to_vtk(smoothed, self.spacing, roi.start,
  55 + "AXIAL")
  56 +
53 # Create vtkPolyData from vtkImageData 57 # Create vtkPolyData from vtkImageData
  58 + print "Generating Polydata"
54 if self.mode == "CONTOUR": 59 if self.mode == "CONTOUR":
  60 + print "Contour"
55 contour = vtk.vtkContourFilter() 61 contour = vtk.vtkContourFilter()
56 contour.SetInput(image) 62 contour.SetInput(image)
57 - contour.SetValue(0, self.min_value) # initial threshold  
58 - contour.SetValue(1, self.max_value) # final threshold  
59 - contour.GetOutput().ReleaseDataFlagOn()  
60 - contour.AddObserver("ProgressEvent", lambda obj,evt:  
61 - self.SendProgress(obj, _("Generating 3D surface..."))) 63 + contour.SetValue(0, 127.5) # initial threshold
  64 + contour.ComputeScalarsOn()
  65 + contour.ComputeGradientsOn()
  66 + contour.ComputeNormalsOn()
62 polydata = contour.GetOutput() 67 polydata = contour.GetOutput()
63 else: #mode == "GRAYSCALE": 68 else: #mode == "GRAYSCALE":
64 mcubes = vtk.vtkMarchingCubes() 69 mcubes = vtk.vtkMarchingCubes()
65 mcubes.SetInput(image) 70 mcubes.SetInput(image)
66 - mcubes.SetValue(0, 255) 71 + mcubes.SetValue(0, 127.5)
67 mcubes.ComputeScalarsOn() 72 mcubes.ComputeScalarsOn()
68 mcubes.ComputeGradientsOn() 73 mcubes.ComputeGradientsOn()
69 mcubes.ComputeNormalsOn() 74 mcubes.ComputeNormalsOn()
70 - mcubes.ThresholdBetween(self.min_value, self.max_value)  
71 - mcubes.GetOutput().ReleaseDataFlagOn()  
72 - mcubes.AddObserver("ProgressEvent", lambda obj,evt:  
73 - self.SendProgress(obj, _("Generating 3D surface...")))  
74 polydata = mcubes.GetOutput() 75 polydata = mcubes.GetOutput()
75 76
  77 + print "Decimating"
76 if self.decimate_reduction: 78 if self.decimate_reduction:
77 - decimation = vtk.vtkQuadricDecimation() 79 + decimation = vtk.vtkDecimatePro()
78 decimation.SetInput(polydata) 80 decimation.SetInput(polydata)
79 decimation.SetTargetReduction(self.decimate_reduction) 81 decimation.SetTargetReduction(self.decimate_reduction)
80 - decimation.GetOutput().ReleaseDataFlagOn()  
81 - decimation.AddObserver("ProgressEvent", lambda obj,evt:  
82 - self.SendProgress(obj, _("Generating 3D surface..."))) 82 + decimation.PreserveTopologyOn()
  83 + decimation.SplittingOff()
83 polydata = decimation.GetOutput() 84 polydata = decimation.GetOutput()
84 85
  86 + print "Smoothing"
85 if self.smooth_iterations and self.smooth_relaxation_factor: 87 if self.smooth_iterations and self.smooth_relaxation_factor:
86 smoother = vtk.vtkSmoothPolyDataFilter() 88 smoother = vtk.vtkSmoothPolyDataFilter()
87 smoother.SetInput(polydata) 89 smoother.SetInput(polydata)
@@ -90,38 +92,16 @@ class SurfaceProcess(multiprocessing.Process): @@ -90,38 +92,16 @@ class SurfaceProcess(multiprocessing.Process):
90 smoother.SetRelaxationFactor(self.smooth_relaxation_factor) 92 smoother.SetRelaxationFactor(self.smooth_relaxation_factor)
91 smoother.FeatureEdgeSmoothingOn() 93 smoother.FeatureEdgeSmoothingOn()
92 smoother.BoundarySmoothingOn() 94 smoother.BoundarySmoothingOn()
93 - smoother.GetOutput().ReleaseDataFlagOn()  
94 - smoother.AddObserver("ProgressEvent", lambda obj,evt:  
95 - self.SendProgress(obj, _("Generating 3D surface...")))  
96 polydata = smoother.GetOutput() 95 polydata = smoother.GetOutput()
97 96
98 -  
99 - if self.keep_largest:  
100 - conn = vtk.vtkPolyDataConnectivityFilter()  
101 - conn.SetInput(polydata)  
102 - conn.SetExtractionModeToLargestRegion()  
103 - conn.AddObserver("ProgressEvent", lambda obj,evt:  
104 - self.SendProgress(obj, _("Generating 3D surface...")))  
105 - polydata = conn.GetOutput()  
106 -  
107 - # Filter used to detect and fill holes. Only fill boundary edges holes.  
108 - #TODO: Hey! This piece of code is the same from  
109 - # polydata_utils.FillSurfaceHole, we need to review this.  
110 - if self.fill_holes:  
111 - filled_polydata = vtk.vtkFillHolesFilter()  
112 - filled_polydata.SetInput(polydata)  
113 - filled_polydata.SetHoleSize(300)  
114 - filled_polydata.AddObserver("ProgressEvent", lambda obj,evt:  
115 - self.SendProgress(obj, _("Generating 3D surface...")))  
116 - polydata = filled_polydata.GetOutput()  
117 -  
118 -  
119 - 97 + print "Saving"
120 filename = tempfile.mktemp() 98 filename = tempfile.mktemp()
121 writer = vtk.vtkXMLPolyDataWriter() 99 writer = vtk.vtkXMLPolyDataWriter()
122 writer.SetInput(polydata) 100 writer.SetInput(polydata)
123 writer.SetFileName(filename) 101 writer.SetFileName(filename)
124 writer.Write() 102 writer.Write()
  103 + print filename
  104 +
  105 + time.sleep(1)
125 106
126 - self.pipe.send(None)  
127 - self.pipe.send(filename) 107 + self.q_out.put(filename)