Commit d4fcee3bc7ba924cd2335565bfd310b07ade0b0d
1 parent
2c2993a8
Exists in
master
and in
5 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() |