Commit d4fcee3bc7ba924cd2335565bfd310b07ade0b0d
1 parent
2c2993a8
Exists in
master
and in
67 other branches
ENH: Optimized memory in DICOM importation window
Showing
3 changed files
with
57 additions
and
28 deletions
Show diff stats
invesalius/gui/dicom_preview_panel.py
| @@ -22,6 +22,7 @@ | @@ -22,6 +22,7 @@ | ||
| 22 | 22 | ||
| 23 | #TODO: To create a beautiful API | 23 | #TODO: To create a beautiful API |
| 24 | import time | 24 | import time |
| 25 | +import tempfile | ||
| 25 | 26 | ||
| 26 | import wx | 27 | import wx |
| 27 | import vtk | 28 | import vtk |
| @@ -34,6 +35,8 @@ from reader import dicom_reader | @@ -34,6 +35,8 @@ from reader import dicom_reader | ||
| 34 | import data.vtk_utils as vtku | 35 | import data.vtk_utils as vtku |
| 35 | import utils | 36 | import utils |
| 36 | import vtkgdcm | 37 | import vtkgdcm |
| 38 | + | ||
| 39 | + | ||
| 37 | NROWS = 3 | 40 | NROWS = 3 |
| 38 | NCOLS = 6 | 41 | NCOLS = 6 |
| 39 | NUM_PREVIEWS = NCOLS*NROWS | 42 | NUM_PREVIEWS = NCOLS*NROWS |
| @@ -102,31 +105,18 @@ class DicomInfo(object): | @@ -102,31 +105,18 @@ class DicomInfo(object): | ||
| 102 | self.subtitle = subtitle | 105 | self.subtitle = subtitle |
| 103 | self._preview = None | 106 | self._preview = None |
| 104 | self.selected = False | 107 | self.selected = False |
| 108 | + self.filename = "" | ||
| 105 | 109 | ||
| 106 | @property | 110 | @property |
| 107 | def preview(self): | 111 | def preview(self): |
| 108 | - rdicom = vtkgdcm.vtkGDCMImageReader() | ||
| 109 | - if self._preview: | ||
| 110 | - return self._preview | ||
| 111 | - else: | ||
| 112 | - rdicom.SetFileName(self.dicom.image.file) | ||
| 113 | - rdicom.Update() | ||
| 114 | - | ||
| 115 | - colorer = vtk.vtkImageMapToWindowLevelColors() | ||
| 116 | - colorer.SetInput(rdicom.GetOutput()) | ||
| 117 | - colorer.SetWindow(float(self.dicom.image.window)) | ||
| 118 | - colorer.SetLevel(float(self.dicom.image.level)) | ||
| 119 | - colorer.SetOutputFormatToRGB() | ||
| 120 | - colorer.Update() | ||
| 121 | - | ||
| 122 | - width, height, z = colorer.GetOutput().GetDimensions() | ||
| 123 | - | ||
| 124 | - r = colorer.GetOutput().GetPointData().GetScalars() | ||
| 125 | - ni = numpy_support.vtk_to_numpy(r) | ||
| 126 | - self.img = wx.ImageFromBuffer(width, height, ni) | ||
| 127 | - self._preview = self.img.Mirror(False) | ||
| 128 | - return self._preview | ||
| 129 | - | 112 | + |
| 113 | + if not self._preview: | ||
| 114 | + bmp = wx.Bitmap(self.dicom.image.thumbnail_path, wx.BITMAP_TYPE_PNG) | ||
| 115 | + self._preview = bmp.ConvertToImage() | ||
| 116 | + return self._preview | ||
| 117 | + | ||
| 118 | + def release_thumbnail(self): | ||
| 119 | + self._preview = None | ||
| 130 | 120 | ||
| 131 | class DicomPaintPanel(wx.Panel): | 121 | class DicomPaintPanel(wx.Panel): |
| 132 | def __init__(self, parent): | 122 | def __init__(self, parent): |
| @@ -238,6 +228,9 @@ class Preview(wx.Panel): | @@ -238,6 +228,9 @@ class Preview(wx.Panel): | ||
| 238 | """ | 228 | """ |
| 239 | Set a dicom to preview. | 229 | Set a dicom to preview. |
| 240 | """ | 230 | """ |
| 231 | + if self.dicom_info: | ||
| 232 | + self.dicom_info.release_thumbnail() | ||
| 233 | + | ||
| 241 | self.dicom_info = dicom_info | 234 | self.dicom_info = dicom_info |
| 242 | self.SetTitle(dicom_info.title) | 235 | self.SetTitle(dicom_info.title) |
| 243 | self.SetSubtitle(dicom_info.subtitle) | 236 | self.SetSubtitle(dicom_info.subtitle) |
| @@ -409,7 +402,6 @@ class DicomPreviewSeries(wx.Panel): | @@ -409,7 +402,6 @@ class DicomPreviewSeries(wx.Panel): | ||
| 409 | def _display_previews(self): | 402 | def _display_previews(self): |
| 410 | initial = self.displayed_position * NCOLS | 403 | initial = self.displayed_position * NCOLS |
| 411 | final = initial + NUM_PREVIEWS | 404 | final = initial + NUM_PREVIEWS |
| 412 | - | ||
| 413 | if len(self.files) < final: | 405 | if len(self.files) < final: |
| 414 | for i in xrange(final-len(self.files)): | 406 | for i in xrange(final-len(self.files)): |
| 415 | try: | 407 | try: |
| @@ -557,7 +549,6 @@ class DicomPreviewSlice(wx.Panel): | @@ -557,7 +549,6 @@ class DicomPreviewSlice(wx.Panel): | ||
| 557 | def _display_previews(self): | 549 | def _display_previews(self): |
| 558 | initial = self.displayed_position * NCOLS | 550 | initial = self.displayed_position * NCOLS |
| 559 | final = initial + NUM_PREVIEWS | 551 | final = initial + NUM_PREVIEWS |
| 560 | - | ||
| 561 | if len(self.files) < final: | 552 | if len(self.files) < final: |
| 562 | for i in xrange(final-len(self.files)): | 553 | for i in xrange(final-len(self.files)): |
| 563 | try: | 554 | try: |
invesalius/reader/dicom.py
| @@ -139,9 +139,10 @@ class Parser(): | @@ -139,9 +139,10 @@ class Parser(): | ||
| 139 | # return None#self.vtkgdcm_reader.GetOutput() | 139 | # return None#self.vtkgdcm_reader.GetOutput() |
| 140 | 140 | ||
| 141 | 141 | ||
| 142 | - def SetDataImage(self, data_image, filename): | 142 | + def SetDataImage(self, data_image, filename, thumbnail_path): |
| 143 | self.data_image = data_image | 143 | self.data_image = data_image |
| 144 | self.filename = self.filepath = filename | 144 | self.filename = self.filepath = filename |
| 145 | + self.thumbnail_path = thumbnail_path | ||
| 145 | 146 | ||
| 146 | def __format_time(self,value): | 147 | def __format_time(self,value): |
| 147 | sp1 = value.split(".") | 148 | sp1 = value.split(".") |
| @@ -1931,6 +1932,7 @@ class Image(object): | @@ -1931,6 +1932,7 @@ class Image(object): | ||
| 1931 | self.size = (parser.GetDimensionX(), parser.GetDimensionY()) | 1932 | self.size = (parser.GetDimensionX(), parser.GetDimensionY()) |
| 1932 | #self.imagedata = parser.GetImageData() | 1933 | #self.imagedata = parser.GetImageData() |
| 1933 | self.bits_allocad = parser._GetBitsAllocated() | 1934 | self.bits_allocad = parser._GetBitsAllocated() |
| 1935 | + self.thumbnail_path = parser.thumbnail_path | ||
| 1934 | 1936 | ||
| 1935 | if (parser.GetImageThickness()): | 1937 | if (parser.GetImageThickness()): |
| 1936 | try: | 1938 | try: |
invesalius/reader/dicom_reader.py
| @@ -19,10 +19,12 @@ | @@ -19,10 +19,12 @@ | ||
| 19 | import os | 19 | import os |
| 20 | import Queue | 20 | import Queue |
| 21 | import threading | 21 | import threading |
| 22 | +import tempfile | ||
| 22 | 23 | ||
| 23 | from multiprocessing import cpu_count | 24 | from multiprocessing import cpu_count |
| 24 | 25 | ||
| 25 | import vtk | 26 | import vtk |
| 27 | +import vtkgdcm | ||
| 26 | import gdcm | 28 | import gdcm |
| 27 | import wx.lib.pubsub as ps | 29 | import wx.lib.pubsub as ps |
| 28 | 30 | ||
| @@ -106,9 +108,8 @@ class LoadDicom(threading.Thread): | @@ -106,9 +108,8 @@ class LoadDicom(threading.Thread): | ||
| 106 | reader.SetFileName(str(filepath)) | 108 | reader.SetFileName(str(filepath)) |
| 107 | 109 | ||
| 108 | if (reader.Read()): | 110 | if (reader.Read()): |
| 109 | - | ||
| 110 | file = reader.GetFile() | 111 | file = reader.GetFile() |
| 111 | - | 112 | + |
| 112 | # Retrieve data set | 113 | # Retrieve data set |
| 113 | dataSet = file.GetDataSet() | 114 | dataSet = file.GetDataSet() |
| 114 | 115 | ||
| @@ -173,6 +174,41 @@ class LoadDicom(threading.Thread): | @@ -173,6 +174,41 @@ class LoadDicom(threading.Thread): | ||
| 173 | data_dict[group][field] = "Invalid Character" | 174 | data_dict[group][field] = "Invalid Character" |
| 174 | 175 | ||
| 175 | 176 | ||
| 177 | + | ||
| 178 | + # -------------- To Create DICOM Thumbnail ----------- | ||
| 179 | + rvtk = vtkgdcm.vtkGDCMImageReader() | ||
| 180 | + rvtk.SetFileName(str(filepath)) | ||
| 181 | + rvtk.Update() | ||
| 182 | + | ||
| 183 | + try: | ||
| 184 | + data = data_dict['0028']['1050'] | ||
| 185 | + level = [float(value) for value in data.split('\\')][0] | ||
| 186 | + data = data_dict['0028']['1051'] | ||
| 187 | + window = [float(value) for value in data.split('\\')][0] | ||
| 188 | + except(KeyError): | ||
| 189 | + level = 300.0 | ||
| 190 | + window = 2000.0 | ||
| 191 | + | ||
| 192 | + colorer = vtk.vtkImageMapToWindowLevelColors() | ||
| 193 | + colorer.SetInput(rvtk.GetOutput()) | ||
| 194 | + colorer.SetWindow(float(window)) | ||
| 195 | + colorer.SetLevel(float(level)) | ||
| 196 | + colorer.SetOutputFormatToRGB() | ||
| 197 | + colorer.Update() | ||
| 198 | + | ||
| 199 | + resample = vtk.vtkImageResample() | ||
| 200 | + resample.SetInput(colorer.GetOutput()) | ||
| 201 | + resample.SetAxisMagnificationFactor ( 0, 0.25 ) | ||
| 202 | + resample.SetAxisMagnificationFactor ( 1, 0.25 ) | ||
| 203 | + resample.SetAxisMagnificationFactor ( 2, 1 ) | ||
| 204 | + resample.Update() | ||
| 205 | + | ||
| 206 | + thumbnail_path = tempfile.mktemp() | ||
| 207 | + | ||
| 208 | + write_png = vtk.vtkPNGWriter() | ||
| 209 | + write_png.SetInput(resample.GetOutput()) | ||
| 210 | + write_png.SetFileName(thumbnail_path) | ||
| 211 | + write_png.Write() | ||
| 176 | 212 | ||
| 177 | # ---------- Refactory -------------------------------------- | 213 | # ---------- Refactory -------------------------------------- |
| 178 | data_dict['invesalius'] = {'orientation_label' : GetImageOrientationLabel(str(filepath))} | 214 | data_dict['invesalius'] = {'orientation_label' : GetImageOrientationLabel(str(filepath))} |
| @@ -190,7 +226,7 @@ class LoadDicom(threading.Thread): | @@ -190,7 +226,7 @@ class LoadDicom(threading.Thread): | ||
| 190 | 226 | ||
| 191 | if not(is_dicom_dir): | 227 | if not(is_dicom_dir): |
| 192 | parser = dicom.Parser() | 228 | parser = dicom.Parser() |
| 193 | - parser.SetDataImage(dict_file[filepath], filepath) | 229 | + parser.SetDataImage(dict_file[filepath], filepath, thumbnail_path) |
| 194 | 230 | ||
| 195 | dcm = dicom.Dicom() | 231 | dcm = dicom.Dicom() |
| 196 | self.l.acquire() | 232 | self.l.acquire() |