Commit 379a62714282b82147d84134864df41cc1975b1e
1 parent
6d9e7e2a
Exists in
master
Using the resample method to calculate the final image size when rescaling (closes #126)
Showing
1 changed file
with
54 additions
and
60 deletions
Show diff stats
invesalius/data/imagedata_utils.py
... | ... | @@ -27,7 +27,7 @@ import vtk |
27 | 27 | import vtkgdcm |
28 | 28 | from wx.lib.pubsub import pub as Publisher |
29 | 29 | |
30 | -from scipy.ndimage import shift | |
30 | +from scipy.ndimage import shift, zoom | |
31 | 31 | from vtk.util import numpy_support |
32 | 32 | |
33 | 33 | import invesalius.constants as const |
... | ... | @@ -69,20 +69,20 @@ def ResampleImage2D(imagedata, px=None, py=None, resolution_percentage = None, |
69 | 69 | dimensions = imagedata.GetDimensions() |
70 | 70 | |
71 | 71 | if resolution_percentage: |
72 | - px = math.ceil(dimensions[0] * resolution_percentage) | |
73 | - py = math.ceil(dimensions[1] * resolution_percentage) | |
74 | - | |
75 | - if abs(extent[1]-extent[3]) < abs(extent[3]-extent[5]): | |
76 | - f = extent[1] | |
77 | - elif abs(extent[1]-extent[5]) < abs(extent[1] - extent[3]): | |
78 | - f = extent[1] | |
79 | - elif abs(extent[3]-extent[5]) < abs(extent[1] - extent[3]): | |
80 | - f = extent[3] | |
72 | + factor_x = resolution_percentage | |
73 | + factor_y = resolution_percentage | |
81 | 74 | else: |
82 | - f = extent[1] | |
75 | + if abs(extent[1]-extent[3]) < abs(extent[3]-extent[5]): | |
76 | + f = extent[1] | |
77 | + elif abs(extent[1]-extent[5]) < abs(extent[1] - extent[3]): | |
78 | + f = extent[1] | |
79 | + elif abs(extent[3]-extent[5]) < abs(extent[1] - extent[3]): | |
80 | + f = extent[3] | |
81 | + else: | |
82 | + f = extent[1] | |
83 | 83 | |
84 | - factor_x = px/float(f+1) | |
85 | - factor_y = py/float(f+1) | |
84 | + factor_x = px/float(f+1) | |
85 | + factor_y = py/float(f+1) | |
86 | 86 | |
87 | 87 | resample = vtk.vtkImageResample() |
88 | 88 | resample.SetInputData(imagedata) |
... | ... | @@ -98,6 +98,35 @@ def ResampleImage2D(imagedata, px=None, py=None, resolution_percentage = None, |
98 | 98 | |
99 | 99 | return resample.GetOutput() |
100 | 100 | |
101 | + | |
102 | +def resize_slice(im_array, resolution_percentage): | |
103 | + """ | |
104 | + Uses ndimage.zoom to resize a slice. | |
105 | + | |
106 | + input: | |
107 | + im_array: slice as a numpy array. | |
108 | + resolution_percentage: percentage of resize. | |
109 | + """ | |
110 | + out = zoom(im_array, resolution_percentage, im_array.dtype, order=2) | |
111 | + return out | |
112 | + | |
113 | + | |
114 | +def read_dcm_slice_as_np(filename, resolution_percentage=1.0): | |
115 | + """ | |
116 | + read a dicom slice file and return the slice as numpy ndarray | |
117 | + """ | |
118 | + dcm_reader = vtkgdcm.vtkGDCMImageReader() | |
119 | + dcm_reader.SetFileName(filename) | |
120 | + dcm_reader.Update() | |
121 | + image = dcm_reader.GetOutput() | |
122 | + if resolution_percentage < 1.0: | |
123 | + image = ResampleImage2D(image, resolution_percentage=resolution_percentage) | |
124 | + dx, dy, dz = image.GetDimensions() | |
125 | + im_array = numpy_support.vtk_to_numpy(image.GetPointData().GetScalars()) | |
126 | + im_array.shape = dy, dx | |
127 | + return im_array | |
128 | + | |
129 | + | |
101 | 130 | def FixGantryTilt(matrix, spacing, tilt): |
102 | 131 | """ |
103 | 132 | Fix gantry tilt given a vtkImageData and the tilt value. Return new |
... | ... | @@ -525,70 +554,35 @@ def dcm2memmap(files, slice_size, orientation, resolution_percentage): |
525 | 554 | message = _("Generating multiplanar visualization...") |
526 | 555 | update_progress= vtk_utils.ShowProgress(len(files) - 1, dialog_type = "ProgressDialog") |
527 | 556 | |
557 | + first_slice = read_dcm_slice_as_np(files[0], resolution_percentage) | |
558 | + slice_size = first_slice.shape[::-1] | |
559 | + | |
528 | 560 | temp_file = tempfile.mktemp() |
529 | 561 | |
530 | 562 | if orientation == 'SAGITTAL': |
531 | - if resolution_percentage == 1.0: | |
532 | - shape = slice_size[0], slice_size[1], len(files) | |
533 | - else: | |
534 | - shape = int(math.ceil(slice_size[0]*resolution_percentage)),\ | |
535 | - int(math.ceil(slice_size[1]*resolution_percentage)), len(files) | |
536 | - | |
563 | + shape = slice_size[0], slice_size[1], len(files) | |
537 | 564 | elif orientation == 'CORONAL': |
538 | - if resolution_percentage == 1.0: | |
539 | - shape = slice_size[1], len(files), slice_size[0] | |
540 | - else: | |
541 | - shape = int(math.ceil(slice_size[1]*resolution_percentage)), len(files),\ | |
542 | - int(math.ceil(slice_size[0]*resolution_percentage)) | |
565 | + shape = slice_size[1], len(files), slice_size[0] | |
543 | 566 | else: |
544 | - if resolution_percentage == 1.0: | |
545 | - shape = len(files), slice_size[1], slice_size[0] | |
546 | - else: | |
547 | - shape = len(files), int(math.ceil(slice_size[1]*resolution_percentage)),\ | |
548 | - int(math.ceil(slice_size[0]*resolution_percentage)) | |
567 | + shape = len(files), slice_size[1], slice_size[0] | |
549 | 568 | |
550 | 569 | matrix = numpy.memmap(temp_file, mode='w+', dtype='int16', shape=shape) |
551 | - dcm_reader = vtkgdcm.vtkGDCMImageReader() | |
552 | - cont = 0 | |
553 | - max_scalar = None | |
554 | - min_scalar = None | |
555 | - | |
556 | 570 | for n, f in enumerate(files): |
557 | - dcm_reader.SetFileName(f) | |
558 | - dcm_reader.Update() | |
559 | - image = dcm_reader.GetOutput() | |
560 | - | |
561 | - if resolution_percentage != 1.0: | |
562 | - image_resized = ResampleImage2D(image, px=None, py=None,\ | |
563 | - resolution_percentage = resolution_percentage, update_progress = None) | |
564 | - | |
565 | - image = image_resized | |
566 | - | |
567 | - min_aux, max_aux = image.GetScalarRange() | |
568 | - if min_scalar is None or min_aux < min_scalar: | |
569 | - min_scalar = min_aux | |
570 | - | |
571 | - if max_scalar is None or max_aux > max_scalar: | |
572 | - max_scalar = max_aux | |
571 | + im_array = read_dcm_slice_as_np(f, resolution_percentage) | |
573 | 572 | |
574 | - array = numpy_support.vtk_to_numpy(image.GetPointData().GetScalars()) | |
575 | 573 | if orientation == 'CORONAL': |
576 | - array.shape = matrix.shape[0], matrix.shape[2] | |
577 | - matrix[:, shape[1] - n - 1, :] = array | |
574 | + matrix[:, shape[1] - n - 1, :] = im_array | |
578 | 575 | elif orientation == 'SAGITTAL': |
579 | - array.shape = matrix.shape[0], matrix.shape[1] | |
580 | 576 | # TODO: Verify if it's necessary to add the slices swapped only in |
581 | 577 | # sagittal rmi or only in # Rasiane's case or is necessary in all |
582 | 578 | # sagittal cases. |
583 | - matrix[:, :, n] = array | |
579 | + matrix[:, :, n] = im_array | |
584 | 580 | else: |
585 | - array.shape = matrix.shape[1], matrix.shape[2] | |
586 | - matrix[n] = array | |
587 | - update_progress(cont,message) | |
588 | - cont += 1 | |
581 | + matrix[n] = im_array | |
582 | + update_progress(n, message) | |
589 | 583 | |
590 | 584 | matrix.flush() |
591 | - scalar_range = min_scalar, max_scalar | |
585 | + scalar_range = matrix.min(), matrix.max() | |
592 | 586 | |
593 | 587 | return matrix, scalar_range, temp_file |
594 | 588 | ... | ... |