Commit e63af012f1c31649c59778351f80ce3e2917b762
1 parent
c899bff4
Exists in
master
and in
5 other branches
ENH: Improved progress bar
Showing
3 changed files
with
102 additions
and
97 deletions
Show diff stats
invesalius/data/surface.py
@@ -377,7 +377,7 @@ class SurfaceManager(): | @@ -377,7 +377,7 @@ class SurfaceManager(): | ||
377 | """ | 377 | """ |
378 | matrix, filename_img, mask, spacing = pubsub_evt.data | 378 | matrix, filename_img, mask, spacing = pubsub_evt.data |
379 | min_value, max_value = mask.threshold_range | 379 | min_value, max_value = mask.threshold_range |
380 | - fill_holes = True | 380 | + fill_holes = False |
381 | 381 | ||
382 | #if len(surface_data) == 5: | 382 | #if len(surface_data) == 5: |
383 | #imagedata, colour, [min_value, max_value], \ | 383 | #imagedata, colour, [min_value, max_value], \ |
@@ -394,7 +394,7 @@ class SurfaceManager(): | @@ -394,7 +394,7 @@ class SurfaceManager(): | ||
394 | 394 | ||
395 | mode = 'CONTOUR' # 'GRAYSCALE' | 395 | mode = 'CONTOUR' # 'GRAYSCALE' |
396 | quality=_('Optimal *') | 396 | quality=_('Optimal *') |
397 | - keep_largest = True | 397 | + keep_largest = False |
398 | surface_name = "" | 398 | surface_name = "" |
399 | colour = mask.colour | 399 | colour = mask.colour |
400 | 400 | ||
@@ -415,19 +415,19 @@ class SurfaceManager(): | @@ -415,19 +415,19 @@ class SurfaceManager(): | ||
415 | #if imagedata_resolution: | 415 | #if imagedata_resolution: |
416 | #imagedata = iu.ResampleImage3D(imagedata, imagedata_resolution) | 416 | #imagedata = iu.ResampleImage3D(imagedata, imagedata_resolution) |
417 | 417 | ||
418 | - #pipeline_size = 4 | ||
419 | - #if decimate_reduction: | ||
420 | - #pipeline_size += 1 | ||
421 | - #if (smooth_iterations and smooth_relaxation_factor): | ||
422 | - #pipeline_size += 1 | 418 | + pipeline_size = 4 |
419 | + if decimate_reduction: | ||
420 | + pipeline_size += 1 | ||
421 | + if (smooth_iterations and smooth_relaxation_factor): | ||
422 | + pipeline_size += 1 | ||
423 | #if fill_holes: | 423 | #if fill_holes: |
424 | - #pipeline_size += 1 | 424 | + # pipeline_size += 1 |
425 | #if keep_largest: | 425 | #if keep_largest: |
426 | - #pipeline_size += 1 | ||
427 | - | 426 | + # pipeline_size += 1 |
427 | + | ||
428 | ## Update progress value in GUI | 428 | ## Update progress value in GUI |
429 | - #UpdateProgress = vu.ShowProgress(pipeline_size) | ||
430 | - #UpdateProgress(0, _("Generating 3D surface...")) | 429 | + UpdateProgress = vu.ShowProgress(pipeline_size) |
430 | + UpdateProgress(0, _("Generating 3D surface...")) | ||
431 | 431 | ||
432 | #filename_img = tempfile.mktemp() | 432 | #filename_img = tempfile.mktemp() |
433 | 433 | ||
@@ -452,7 +452,6 @@ class SurfaceManager(): | @@ -452,7 +452,6 @@ class SurfaceManager(): | ||
452 | piece_size = 20 | 452 | piece_size = 20 |
453 | 453 | ||
454 | n_pieces = int(round(matrix.shape[0] / piece_size + 0.5, 0)) | 454 | n_pieces = int(round(matrix.shape[0] / piece_size + 0.5, 0)) |
455 | - print "n_pieces", n_pieces, matrix.shape | ||
456 | 455 | ||
457 | q_in = multiprocessing.Queue() | 456 | q_in = multiprocessing.Queue() |
458 | q_out = multiprocessing.Queue() | 457 | q_out = multiprocessing.Queue() |
@@ -463,8 +462,7 @@ class SurfaceManager(): | @@ -463,8 +462,7 @@ class SurfaceManager(): | ||
463 | matrix.shape, matrix.dtype, spacing, | 462 | matrix.shape, matrix.dtype, spacing, |
464 | mode, min_value, max_value, | 463 | mode, min_value, max_value, |
465 | decimate_reduction, smooth_relaxation_factor, | 464 | decimate_reduction, smooth_relaxation_factor, |
466 | - smooth_iterations, language, fill_holes, keep_largest, | ||
467 | - flip_image, q_in, q_out) | 465 | + smooth_iterations, language, flip_image, q_in, q_out) |
468 | p.append(sp) | 466 | p.append(sp) |
469 | sp.start() | 467 | sp.start() |
470 | 468 | ||
@@ -478,6 +476,18 @@ class SurfaceManager(): | @@ -478,6 +476,18 @@ class SurfaceManager(): | ||
478 | for i in p: | 476 | for i in p: |
479 | q_in.put(None) | 477 | q_in.put(None) |
480 | 478 | ||
479 | + none_count = 1 | ||
480 | + while 1: | ||
481 | + msg = pipe_out.recv() | ||
482 | + if(msg is None): | ||
483 | + none_count += 1 | ||
484 | + else: | ||
485 | + UpdateProgress(msg[0]/(n_pieces * pipeline_size), msg[1]) | ||
486 | + | ||
487 | + if none_count > n_pieces: | ||
488 | + break | ||
489 | + | ||
490 | + | ||
481 | polydata_append = vtk.vtkAppendPolyData() | 491 | polydata_append = vtk.vtkAppendPolyData() |
482 | t = n_pieces | 492 | t = n_pieces |
483 | while t: | 493 | while t: |
@@ -490,13 +500,18 @@ class SurfaceManager(): | @@ -490,13 +500,18 @@ class SurfaceManager(): | ||
490 | 500 | ||
491 | t -= 1 | 501 | t -= 1 |
492 | polydata = polydata_append.GetOutput() | 502 | polydata = polydata_append.GetOutput() |
493 | - | ||
494 | clean = vtk.vtkCleanPolyData() | 503 | clean = vtk.vtkCleanPolyData() |
504 | + clean.AddObserver("ProgressEvent", lambda obj,evt: | ||
505 | + UpdateProgress(obj, _("Generating 3D surface..."))) | ||
495 | clean.SetInput(polydata) | 506 | clean.SetInput(polydata) |
496 | clean.PointMergingOn() | 507 | clean.PointMergingOn() |
508 | + clean.Update() | ||
497 | polydata = clean.GetOutput() | 509 | polydata = clean.GetOutput() |
498 | 510 | ||
511 | + | ||
499 | smoother = vtk.vtkWindowedSincPolyDataFilter() | 512 | smoother = vtk.vtkWindowedSincPolyDataFilter() |
513 | + smoother.AddObserver("ProgressEvent", lambda obj,evt: | ||
514 | + UpdateProgress(obj, _("Generating 3D surface..."))) | ||
500 | smoother.SetInput(polydata) | 515 | smoother.SetInput(polydata) |
501 | smoother.SetNumberOfIterations(smooth_iterations) | 516 | smoother.SetNumberOfIterations(smooth_iterations) |
502 | smoother.SetFeatureAngle(120) | 517 | smoother.SetFeatureAngle(120) |
@@ -508,29 +523,48 @@ class SurfaceManager(): | @@ -508,29 +523,48 @@ class SurfaceManager(): | ||
508 | smoother.Update() | 523 | smoother.Update() |
509 | polydata = smoother.GetOutput() | 524 | polydata = smoother.GetOutput() |
510 | 525 | ||
526 | + if keep_largest: | ||
527 | + conn = vtk.vtkPolyDataConnectivityFilter() | ||
528 | + conn.SetInput(polydata) | ||
529 | + conn.SetExtractionModeToLargestRegion() | ||
530 | + conn.AddObserver("ProgressEvent", lambda obj,evt: | ||
531 | + UpdateProgress(obj, _("Generating 3D surface..."))) | ||
532 | + polydata = conn.GetOutput() | ||
533 | + | ||
534 | + | ||
535 | + # Filter used to detect and fill holes. Only fill boundary edges holes. | ||
536 | + #TODO: Hey! This piece of code is the same from | ||
537 | + # polydata_utils.FillSurfaceHole, we need to review this. | ||
538 | + if fill_holes: | ||
539 | + filled_polydata = vtk.vtkFillHolesFilter() | ||
540 | + filled_polydata.SetInput(polydata) | ||
541 | + filled_polydata.SetHoleSize(300) | ||
542 | + #filled_polydata.AddObserver("ProgressEvent", lambda obj,evt: | ||
543 | + # UpdateProgress(obj, _("Generating 3D surface..."))) | ||
544 | + polydata = filled_polydata.GetOutput() | ||
511 | 545 | ||
512 | normals = vtk.vtkPolyDataNormals() | 546 | normals = vtk.vtkPolyDataNormals() |
547 | + normals.AddObserver("ProgressEvent", lambda obj,evt: | ||
548 | + UpdateProgress(obj, _("Generating 3D surface..."))) | ||
513 | normals.SetInput(polydata) | 549 | normals.SetInput(polydata) |
514 | normals.SetFeatureAngle(80) | 550 | normals.SetFeatureAngle(80) |
515 | normals.AutoOrientNormalsOn() | 551 | normals.AutoOrientNormalsOn() |
552 | + normals.Update() | ||
516 | polydata = normals.GetOutput() | 553 | polydata = normals.GetOutput() |
517 | - #decimation = vtk.vtkDecimatePro() | ||
518 | - #decimation.SetInput(polydata) | ||
519 | - #decimation.SetTargetReduction(0.3) | ||
520 | - #decimation.PreserveTopologyOn() | ||
521 | - #decimation.SplittingOff() | ||
522 | - #decimation.BoundaryVertexDeletionOff() | ||
523 | - #polydata = decimation.GetOutput() | ||
524 | 554 | ||
525 | # Improve performance | 555 | # Improve performance |
526 | stripper = vtk.vtkStripper() | 556 | stripper = vtk.vtkStripper() |
557 | + stripper.AddObserver("ProgressEvent", lambda obj,evt: | ||
558 | + UpdateProgress(obj, _("Generating 3D surface..."))) | ||
527 | stripper.SetInput(polydata) | 559 | stripper.SetInput(polydata) |
528 | stripper.PassThroughCellIdsOn() | 560 | stripper.PassThroughCellIdsOn() |
529 | stripper.PassThroughPointIdsOn() | 561 | stripper.PassThroughPointIdsOn() |
562 | + stripper.Update() | ||
563 | + polydata = stripper.GetOutput() | ||
530 | 564 | ||
531 | # Map polygonal data (vtkPolyData) to graphics primitives. | 565 | # Map polygonal data (vtkPolyData) to graphics primitives. |
532 | mapper = vtk.vtkPolyDataMapper() | 566 | mapper = vtk.vtkPolyDataMapper() |
533 | - mapper.SetInput(stripper.GetOutput()) | 567 | + mapper.SetInput(polydata) |
534 | mapper.ScalarVisibilityOff() | 568 | mapper.ScalarVisibilityOff() |
535 | mapper.ImmediateModeRenderingOn() # improve performance | 569 | mapper.ImmediateModeRenderingOn() # improve performance |
536 | 570 | ||
@@ -601,15 +635,16 @@ class SurfaceManager(): | @@ -601,15 +635,16 @@ class SurfaceManager(): | ||
601 | # Save actor for future management tasks | 635 | # Save actor for future management tasks |
602 | self.actors_dict[surface.index] = actor | 636 | self.actors_dict[surface.index] = actor |
603 | 637 | ||
604 | - | ||
605 | - ps.Publisher().sendMessage('Update status text in GUI', | ||
606 | - _("Ready")) | ||
607 | - | ||
608 | ps.Publisher().sendMessage('Update surface info in GUI', | 638 | ps.Publisher().sendMessage('Update surface info in GUI', |
609 | (surface.index, surface.name, | 639 | (surface.index, surface.name, |
610 | surface.colour, surface.volume, | 640 | surface.colour, surface.volume, |
611 | surface.transparency)) | 641 | surface.transparency)) |
612 | 642 | ||
643 | + UpdateProgress(0, _("Ready")) | ||
644 | + UpdateProgress(0, _("Ready")) | ||
645 | + ps.Publisher().sendMessage('Update status text in GUI', | ||
646 | + _("Ready")) | ||
647 | + | ||
613 | ps.Publisher().sendMessage('End busy cursor') | 648 | ps.Publisher().sendMessage('End busy cursor') |
614 | 649 | ||
615 | 650 |
invesalius/data/surface_process.py
@@ -13,8 +13,7 @@ class SurfaceProcess(multiprocessing.Process): | @@ -13,8 +13,7 @@ class SurfaceProcess(multiprocessing.Process): | ||
13 | 13 | ||
14 | def __init__(self, pipe, filename, shape, dtype, spacing, mode, min_value, max_value, | 14 | def __init__(self, pipe, filename, shape, dtype, spacing, mode, min_value, max_value, |
15 | decimate_reduction, smooth_relaxation_factor, | 15 | decimate_reduction, smooth_relaxation_factor, |
16 | - smooth_iterations, language, fill_holes, keep_largest, | ||
17 | - flip_image, q_in, q_out): | 16 | + smooth_iterations, language, flip_image, q_in, q_out): |
18 | 17 | ||
19 | multiprocessing.Process.__init__(self) | 18 | multiprocessing.Process.__init__(self) |
20 | self.pipe = pipe | 19 | self.pipe = pipe |
@@ -27,8 +26,6 @@ class SurfaceProcess(multiprocessing.Process): | @@ -27,8 +26,6 @@ class SurfaceProcess(multiprocessing.Process): | ||
27 | self.smooth_relaxation_factor = smooth_relaxation_factor | 26 | self.smooth_relaxation_factor = smooth_relaxation_factor |
28 | self.smooth_iterations = smooth_iterations | 27 | self.smooth_iterations = smooth_iterations |
29 | self.language = language | 28 | self.language = language |
30 | - self.fill_holes = fill_holes | ||
31 | - self.keep_largest = keep_largest | ||
32 | self.flip_image = flip_image | 29 | self.flip_image = flip_image |
33 | self.q_in = q_in | 30 | self.q_in = q_in |
34 | self.q_out = q_out | 31 | self.q_out = q_out |
@@ -40,7 +37,6 @@ class SurfaceProcess(multiprocessing.Process): | @@ -40,7 +37,6 @@ class SurfaceProcess(multiprocessing.Process): | ||
40 | shape=self.shape) | 37 | shape=self.shape) |
41 | while 1: | 38 | while 1: |
42 | roi = self.q_in.get() | 39 | roi = self.q_in.get() |
43 | - print roi | ||
44 | if roi is None: | 40 | if roi is None: |
45 | break | 41 | break |
46 | self.CreateSurface(roi) | 42 | self.CreateSurface(roi) |
@@ -60,77 +56,52 @@ class SurfaceProcess(multiprocessing.Process): | @@ -60,77 +56,52 @@ class SurfaceProcess(multiprocessing.Process): | ||
60 | flip.Update() | 56 | flip.Update() |
61 | # Create vtkPolyData from vtkImageData | 57 | # Create vtkPolyData from vtkImageData |
62 | #print "Generating Polydata" | 58 | #print "Generating Polydata" |
63 | - #if self.mode == "CONTOUR": | 59 | + if self.mode == "CONTOUR": |
64 | #print "Contour" | 60 | #print "Contour" |
65 | - #contour = vtk.vtkContourFilter() | ||
66 | - #contour.SetInput(image) | ||
67 | - #contour.SetValue(0, self.min_value) # initial threshold | ||
68 | - #contour.SetValue(1, self.max_value) # final threshold | ||
69 | - #contour.ComputeScalarsOn() | ||
70 | - #contour.ComputeGradientsOn() | ||
71 | - #contour.ComputeNormalsOn() | ||
72 | - #polydata = contour.GetOutput() | ||
73 | - #else: #mode == "GRAYSCALE": | ||
74 | - mcubes = vtk.vtkMarchingCubes() | ||
75 | - mcubes.SetInput(flip.GetOutput()) | ||
76 | - mcubes.SetValue(0, self.min_value) | ||
77 | - mcubes.SetValue(1, self.max_value) | ||
78 | - mcubes.ComputeScalarsOff() | ||
79 | - mcubes.ComputeGradientsOff() | ||
80 | - mcubes.ComputeNormalsOff() | ||
81 | - polydata = mcubes.GetOutput() | 61 | + contour = vtk.vtkContourFilter() |
62 | + contour.SetInput(flip.GetOutput()) | ||
63 | + contour.SetValue(0, self.min_value) # initial threshold | ||
64 | + contour.SetValue(1, self.max_value) # final threshold | ||
65 | + contour.ComputeScalarsOn() | ||
66 | + contour.ComputeGradientsOn() | ||
67 | + contour.ComputeNormalsOn() | ||
68 | + contour.AddObserver("ProgressEvent", lambda obj,evt: | ||
69 | + self.SendProgress(obj, _("Generating 3D surface..."))) | ||
70 | + polydata = contour.GetOutput() | ||
71 | + else: #mode == "GRAYSCALE": | ||
72 | + mcubes = vtk.vtkMarchingCubes() | ||
73 | + mcubes.SetInput(flip.GetOutput()) | ||
74 | + mcubes.SetValue(0, self.min_value) | ||
75 | + mcubes.SetValue(1, self.max_value) | ||
76 | + mcubes.ComputeScalarsOff() | ||
77 | + mcubes.ComputeGradientsOff() | ||
78 | + mcubes.ComputeNormalsOff() | ||
79 | + mcubes.AddObserver("ProgressEvent", lambda obj,evt: | ||
80 | + self.SendProgress(obj, _("Generating 3D surface..."))) | ||
81 | + polydata = mcubes.GetOutput() | ||
82 | 82 | ||
83 | triangle = vtk.vtkTriangleFilter() | 83 | triangle = vtk.vtkTriangleFilter() |
84 | triangle.SetInput(polydata) | 84 | triangle.SetInput(polydata) |
85 | + triangle.AddObserver("ProgressEvent", lambda obj,evt: | ||
86 | + self.SendProgress(obj, _("Generating 3D surface..."))) | ||
85 | triangle.Update() | 87 | triangle.Update() |
86 | polydata = triangle.GetOutput() | 88 | polydata = triangle.GetOutput() |
87 | 89 | ||
88 | - bounds = polydata.GetBounds() | ||
89 | - origin = ((bounds[1] + bounds[0]) / 2.0, (bounds[3] + bounds[2])/2.0, | ||
90 | - (bounds[5] + bounds[4]) / 2.0) | ||
91 | - | ||
92 | - print "Bounds is", bounds | ||
93 | - print "origin is", origin | ||
94 | - | ||
95 | - #print "Decimating" | ||
96 | - decimation = vtk.vtkDecimatePro() | ||
97 | - decimation.SetInput(polydata) | ||
98 | - decimation.SetTargetReduction(0.3) | ||
99 | - #decimation.PreserveTopologyOn() | ||
100 | - decimation.SplittingOff() | ||
101 | - decimation.BoundaryVertexDeletionOff() | ||
102 | - polydata = decimation.GetOutput() | ||
103 | - | ||
104 | - #decimation = vtk.vtkQuadricClustering() | ||
105 | - #decimation.SetInput(polydata) | ||
106 | - #decimation.AutoAdjustNumberOfDivisionsOff() | ||
107 | - #decimation.SetDivisionOrigin(0, 0, 0) | ||
108 | - #decimation.SetDivisionSpacing(self.spacing) | ||
109 | - #decimation.SetFeaturePointsAngle(80) | ||
110 | - #decimation.UseFeaturePointsOn() | ||
111 | - #decimation.UseFeatureEdgesOn() | ||
112 | - #ecimation.CopyCellDataOn() | 90 | + if self.decimate_reduction: |
91 | + | ||
92 | + #print "Decimating" | ||
93 | + decimation = vtk.vtkDecimatePro() | ||
94 | + decimation.SetInput(polydata) | ||
95 | + decimation.SetTargetReduction(0.3) | ||
96 | + decimation.AddObserver("ProgressEvent", lambda obj,evt: | ||
97 | + self.SendProgress(obj, _("Generating 3D surface..."))) | ||
98 | + #decimation.PreserveTopologyOn() | ||
99 | + decimation.SplittingOff() | ||
100 | + decimation.BoundaryVertexDeletionOff() | ||
101 | + polydata = decimation.GetOutput() | ||
102 | + | ||
103 | + self.pipe.send(None) | ||
113 | 104 | ||
114 | - #print "Division", decimation.GetNumberOfDivisions() | ||
115 | - | ||
116 | - #polydata = decimation.GetOutput() | ||
117 | - | ||
118 | - #if self.smooth_iterations and self.smooth_relaxation_factor: | ||
119 | - #print "Smoothing" | ||
120 | - #smoother = vtk.vtkWindowedSincPolyDataFilter() | ||
121 | - #smoother.SetInput(polydata) | ||
122 | - #smoother.SetNumberOfIterations(self.smooth_iterations) | ||
123 | - #smoother.SetFeatureAngle(120) | ||
124 | - #smoother.SetNumberOfIterations(30) | ||
125 | - #smoother.BoundarySmoothingOn() | ||
126 | - #smoother.SetPassBand(0.01) | ||
127 | - #smoother.FeatureEdgeSmoothingOn() | ||
128 | - #smoother.NonManifoldSmoothingOn() | ||
129 | - #smoother.NormalizeCoordinatesOn() | ||
130 | - #smoother.Update() | ||
131 | - #polydata = smoother.GetOutput() | ||
132 | - | ||
133 | - print "Saving" | ||
134 | filename = tempfile.mktemp(suffix='_%s.vtp' % (self.pid)) | 105 | filename = tempfile.mktemp(suffix='_%s.vtp' % (self.pid)) |
135 | writer = vtk.vtkXMLPolyDataWriter() | 106 | writer = vtk.vtkXMLPolyDataWriter() |
136 | writer.SetInput(polydata) | 107 | writer.SetInput(polydata) |
invesalius/data/vtk_utils.py
@@ -74,7 +74,6 @@ def ShowProgress(number_of_filters = 1, | @@ -74,7 +74,6 @@ def ShowProgress(number_of_filters = 1, | ||
74 | 74 | ||
75 | # final progress status value | 75 | # final progress status value |
76 | progress[0] = progress[0] + ratio*difference | 76 | progress[0] = progress[0] + ratio*difference |
77 | - | ||
78 | # Tell GUI to update progress status value | 77 | # Tell GUI to update progress status value |
79 | if (dialog_type == "GaugeProgress"): | 78 | if (dialog_type == "GaugeProgress"): |
80 | ps.Publisher().sendMessage('Update status in GUI', | 79 | ps.Publisher().sendMessage('Update status in GUI', |