Commit a724a203ef29718751ee50e146b33b2b9accc8ab
1 parent
a3614eda
Exists in
master
and in
67 other branches
ENH: Generating surface using multiprocessing and with memmap
Showing
4 changed files
with
156 additions
and
147 deletions
Show diff stats
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) |