Commit c020e9044bc39e052bad3910a09fd2ad783ec787
1 parent
f3bf4279
Exists in
master
and in
68 other branches
ENH: Import modularization and implementation, working both command line and int…
…erface (still working on slices preview)
Showing
7 changed files
with
268 additions
and
104 deletions
Show diff stats
invesalius/control.py
@@ -9,6 +9,7 @@ import project as prj | @@ -9,6 +9,7 @@ import project as prj | ||
9 | import data.imagedata_utils as utils | 9 | import data.imagedata_utils as utils |
10 | import data.surface as surface | 10 | import data.surface as surface |
11 | import data.volume as volume | 11 | import data.volume as volume |
12 | +import reader.dicom_grouper | ||
12 | import gui.dialogs as dialog | 13 | import gui.dialogs as dialog |
13 | import reader.dicom_reader as dcm | 14 | import reader.dicom_reader as dcm |
14 | import reader.analyze_reader as analyze | 15 | import reader.analyze_reader as analyze |
@@ -23,23 +24,125 @@ class Controller(): | @@ -23,23 +24,125 @@ class Controller(): | ||
23 | self.__bind_events() | 24 | self.__bind_events() |
24 | 25 | ||
25 | def __bind_events(self): | 26 | def __bind_events(self): |
26 | - ps.Publisher().subscribe(self.ImportDirectory, 'Import directory') | 27 | + ps.Publisher().subscribe(self.OnImportMedicalImages, 'Import directory') |
27 | ps.Publisher().subscribe(self.StartImportPanel, "Load data to import panel") | 28 | ps.Publisher().subscribe(self.StartImportPanel, "Load data to import panel") |
28 | ps.Publisher().subscribe(self.LoadRaycastingPreset, | 29 | ps.Publisher().subscribe(self.LoadRaycastingPreset, |
29 | 'Load raycasting preset') | 30 | 'Load raycasting preset') |
30 | ps.Publisher().subscribe(self.SaveRaycastingPreset, | 31 | ps.Publisher().subscribe(self.SaveRaycastingPreset, |
31 | 'Save raycasting preset') | 32 | 'Save raycasting preset') |
33 | + ps.Publisher().subscribe(self.OnOpenDicomGroup, | ||
34 | + 'Open DICOM group') | ||
32 | 35 | ||
33 | def StartImportPanel(self, pubsub_evt): | 36 | def StartImportPanel(self, pubsub_evt): |
34 | # path to directory | 37 | # path to directory |
35 | path = pubsub_evt.data | 38 | path = pubsub_evt.data |
36 | 39 | ||
37 | # retrieve DICOM files splited into groups | 40 | # retrieve DICOM files splited into groups |
38 | - dicom_series = dcm.GetDicomGroups(path) | ||
39 | - ps.Publisher().sendMessage("Load import panel", dicom_series) | 41 | + patient_series = dcm.GetDicomGroups(path) |
42 | + ps.Publisher().sendMessage("Load import panel", patient_series) | ||
43 | + first_patient = patient_series[0] | ||
44 | + #ps.Publisher().sendMessage("Load dicom preview", first_patient) | ||
45 | + | ||
46 | + def OnImportMedicalImages(self, pubsub_evt): | ||
47 | + directory = pubsub_evt.data | ||
48 | + self.ImportMedicalImages(directory) | ||
49 | + | ||
50 | + def ImportMedicalImages(self, directory): | ||
51 | + # OPTION 1: DICOM? | ||
52 | + patients_groups = dcm.GetDicomGroups(directory) | ||
53 | + if len(patients_groups): | ||
54 | + group = dcm.SelectLargerDicomGroup(patients_groups) | ||
55 | + imagedata, dicom = self.OpenDicomGroup(group, gui=False) | ||
56 | + self.CreateDicomProject(imagedata, dicom) | ||
57 | + # OPTION 2: ANALYZE? | ||
58 | + else: | ||
59 | + imagedata = analyze.ReadDirectory(directory) | ||
60 | + if imagedata: | ||
61 | + self.CreateAnalyzeProject(imagedata) | ||
62 | + # OPTION 3: Nothing... | ||
63 | + else: | ||
64 | + print "No medical images found on given directory" | ||
65 | + return | ||
66 | + self.LoadProject() | ||
67 | + | ||
68 | + def LoadProject(self): | ||
69 | + proj = prj.Project() | ||
70 | + ps.Publisher().sendMessage('Set project name', proj.name) | ||
71 | + ps.Publisher().sendMessage('Load slice to viewer', (proj.imagedata)) | ||
72 | + self.LoadImagedataInfo() # TODO: where do we insert this <<<? | ||
73 | + ps.Publisher().sendMessage('Bright and contrast adjustment image',\ | ||
74 | + (proj.window, proj.level)) | ||
75 | + ps.Publisher().sendMessage('Update window level value',\ | ||
76 | + (proj.window, proj.level)) | ||
77 | + ps.Publisher().sendMessage('Show content panel') | ||
78 | + ps.Publisher().sendMessage('Update AUI') | ||
79 | + | ||
80 | + def CreateAnalyzeProject(self, imagedata): | ||
81 | + proj = prj.Project() | ||
82 | + proj.name = "Untitled" | ||
83 | + proj.SetAcquisitionModality("MRI") | ||
84 | + proj.imagedata = imagedata | ||
85 | + #TODO: Verify if all Analyse are in AXIAL orientation | ||
86 | + proj.original_orientation = const.AXIAL | ||
87 | + proj.threshold_range = imagedata.GetScalarRange() | ||
88 | + proj.window = proj.threshold_range[1] - proj.threshold_range[0] | ||
89 | + proj.level (0.5 * (proj.threshold_range[1] + proj.threshold_range[0])) | ||
90 | + | ||
91 | + const.THRESHOLD_OUTVALUE = proj.threshold_range[0] | ||
92 | + const.THRESHOLD_INVALUE = proj.threshold_range[1] | ||
93 | + const.WINDOW_LEVEL['Default'] = (proj.window, proj.level) | ||
94 | + const.WINDOW_LEVEL['Manual'] = (proj.window, proj.level) | ||
40 | 95 | ||
41 | - #ps.Publisher().sendMessage("Load dicom preview", series_preview) | ||
42 | 96 | ||
97 | + def CreateDicomProject(self, imagedata, dicom): | ||
98 | + name_to_const = {"AXIAL":const.AXIAL, | ||
99 | + "CORONAL":const.CORONAL, | ||
100 | + "SAGITTAL":const.SAGITAL} | ||
101 | + | ||
102 | + proj = prj.Project() | ||
103 | + proj.name = dicom.patient.name | ||
104 | + proj.SetAcquisitionModality(dicom.acquisition.modality) | ||
105 | + proj.imagedata = imagedata | ||
106 | + proj.original_orientation =\ | ||
107 | + name_to_const[dicom.image.orientation_label] | ||
108 | + proj.window = float(dicom.image.window) | ||
109 | + proj.level = float(dicom.image.level) | ||
110 | + proj.threshold_range = imagedata.GetScalarRange() | ||
111 | + | ||
112 | + const.THRESHOLD_OUTVALUE = proj.threshold_range[0] | ||
113 | + const.THRESHOLD_INVALUE = proj.threshold_range[1] | ||
114 | + const.WINDOW_LEVEL['Default'] = (proj.window, proj.level) | ||
115 | + const.WINDOW_LEVEL['Manual'] = (proj.window, proj.level) | ||
116 | + | ||
117 | + def OnOpenDicomGroup(self, pubsub_evt): | ||
118 | + group = pubsub_evt.data | ||
119 | + imagedata, dicom = self.OpenDicomGroup(group, gui=False) | ||
120 | + self.CreateDicomProject(imagedata, dicom) | ||
121 | + self.LoadProject() | ||
122 | + | ||
123 | + def OpenDicomGroup(self, dicom_group, gui=True): | ||
124 | + | ||
125 | + # Retrieve general DICOM headers | ||
126 | + dicom = dicom_group.GetDicomSample() | ||
127 | + | ||
128 | + # Create imagedata | ||
129 | + filelist = dicom_group.GetFilenameList() | ||
130 | + zspacing = dicom_group.zspacing | ||
131 | + imagedata = utils.CreateImageData(filelist, zspacing) | ||
132 | + | ||
133 | + # 1(a): Fix gantry tilt, if any | ||
134 | + tilt_value = dicom.acquisition.tilt | ||
135 | + if (tilt_value) and (gui): | ||
136 | + # Tell user gantry tilt and fix, according to answer | ||
137 | + message = "Fix gantry tilt applying the degrees bellow" | ||
138 | + value = -1*tilt_value | ||
139 | + tilt_value = dialog.ShowNumberDialog(message, value) | ||
140 | + imagedata = utils.FixGantryTilt(imagedata, tilt_value) | ||
141 | + elif (tilt_value) and not (gui): | ||
142 | + tilt_value = -1*tilt_value | ||
143 | + imagedata = utils.FixGantryTilt(imagedata, tilt_value) | ||
144 | + | ||
145 | + return imagedata, dicom | ||
43 | 146 | ||
44 | def ImportDirectory(self, pubsub_evt=None, dir_=None): | 147 | def ImportDirectory(self, pubsub_evt=None, dir_=None): |
45 | """ | 148 | """ |
@@ -84,19 +187,20 @@ class Controller(): | @@ -84,19 +187,20 @@ class Controller(): | ||
84 | else: | 187 | else: |
85 | "No DICOM files were found. Trying to read with ITK..." | 188 | "No DICOM files were found. Trying to read with ITK..." |
86 | imagedata = analyze.ReadDirectory(dir_) | 189 | imagedata = analyze.ReadDirectory(dir_) |
87 | - acquisition_modality = "MRI" | 190 | + if imagedata: |
191 | + acquisition_modality = "MRI" | ||
88 | 192 | ||
89 | - #TODO: Verify if all Analyse is AXIAL orientation | ||
90 | - orientation = const.AXIAL | 193 | + #TODO: Verify if all Analyse is AXIAL orientation |
194 | + orientation = const.AXIAL | ||
91 | 195 | ||
92 | - proj.SetAcquisitionModality(acquisition_modality) | ||
93 | - proj.imagedata = imagedata | ||
94 | - proj.original_orientation = orientation | ||
95 | - threshold_range = proj.imagedata.GetScalarRange() | ||
96 | - proj.window = window = threshold_range[1] - threshold_range[0] | ||
97 | - proj.level = level = (0.5 * (threshold_range[1] + threshold_range[0])) | 196 | + proj.SetAcquisitionModality(acquisition_modality) |
197 | + proj.imagedata = imagedata | ||
198 | + proj.original_orientation = orientation | ||
199 | + threshold_range = proj.imagedata.GetScalarRange() | ||
200 | + proj.window = window = threshold_range[1] - threshold_range[0] | ||
201 | + proj.level = level = (0.5 * (threshold_range[1] + threshold_range[0])) | ||
98 | 202 | ||
99 | - ps.Publisher().sendMessage('Update window level value',\ | 203 | + ps.Publisher().sendMessage('Update window level value',\ |
100 | (proj.window, proj.level)) | 204 | (proj.window, proj.level)) |
101 | 205 | ||
102 | if not imagedata: | 206 | if not imagedata: |
invesalius/data/imagedata_utils.py
1 | import math | 1 | import math |
2 | import vtk | 2 | import vtk |
3 | +import vtkgdcm | ||
4 | + | ||
5 | +import constants as const | ||
3 | 6 | ||
4 | # TODO: Test cases which are originally in sagittal/coronal orientation | 7 | # TODO: Test cases which are originally in sagittal/coronal orientation |
5 | # and have gantry | 8 | # and have gantry |
@@ -162,3 +165,52 @@ def ExtractVOI(imagedata,xi,xf,yi,yf,zi,zf): | @@ -162,3 +165,52 @@ def ExtractVOI(imagedata,xi,xf,yi,yf,zi,zf): | ||
162 | voi.SetSampleRate(1, 1, 1) | 165 | voi.SetSampleRate(1, 1, 1) |
163 | voi.Update() | 166 | voi.Update() |
164 | return voi.GetOutput() | 167 | return voi.GetOutput() |
168 | + | ||
169 | +def CreateImageData(filelist, zspacing): | ||
170 | + | ||
171 | + if not(const.REDUCE_IMAGEDATA_QUALITY): | ||
172 | + array = vtk.vtkStringArray() | ||
173 | + for x in xrange(len(filelist)): | ||
174 | + array.InsertValue(x,filelist[x]) | ||
175 | + | ||
176 | + reader = vtkgdcm.vtkGDCMImageReader() | ||
177 | + reader.SetFileNames(array) | ||
178 | + reader.Update() | ||
179 | + | ||
180 | + # The zpacing is a DicomGroup property, so we need to set it | ||
181 | + imagedata = vtk.vtkImageData() | ||
182 | + imagedata.DeepCopy(reader.GetOutput()) | ||
183 | + spacing = imagedata.GetSpacing() | ||
184 | + imagedata.SetSpacing(spacing[0], spacing[1], zspacing) | ||
185 | + else: | ||
186 | + # Reformat each slice and future append them | ||
187 | + appender = vtk.vtkImageAppend() | ||
188 | + appender.SetAppendAxis(2) #Define Stack in Z | ||
189 | + | ||
190 | + # Reformat each slice | ||
191 | + for x in xrange(len(filelist)): | ||
192 | + # TODO: We need to check this automatically according | ||
193 | + # to each computer's architecture | ||
194 | + # If the resolution of the matrix is too large | ||
195 | + reader = vtkgdcm.vtkGDCMImageReader() | ||
196 | + reader.SetFileName(filelist[x]) | ||
197 | + reader.Update() | ||
198 | + | ||
199 | + #Resample image in x,y dimension | ||
200 | + slice_imagedata = ResampleImage2D(reader.GetOutput(), 256) | ||
201 | + | ||
202 | + #Stack images in Z axes | ||
203 | + appender.AddInput(slice_imagedata) | ||
204 | + appender.Update() | ||
205 | + | ||
206 | + # The zpacing is a DicomGroup property, so we need to set it | ||
207 | + imagedata = vtk.vtkImageData() | ||
208 | + imagedata.DeepCopy(appender.GetOutput()) | ||
209 | + spacing = imagedata.GetSpacing() | ||
210 | + | ||
211 | + imagedata.SetSpacing(spacing[0], spacing[1], zspacing) | ||
212 | + | ||
213 | + imagedata.Update() | ||
214 | + return imagedata | ||
215 | + | ||
216 | + |
invesalius/gui/dicom_preview_panel.py
@@ -31,6 +31,27 @@ class SerieEvent(PreviewEvent): | @@ -31,6 +31,27 @@ class SerieEvent(PreviewEvent): | ||
31 | def __init__(self , evtType, id): | 31 | def __init__(self , evtType, id): |
32 | super(SerieEvent, self).__init__(evtType, id) | 32 | super(SerieEvent, self).__init__(evtType, id) |
33 | 33 | ||
34 | +class DicomImageData(object): | ||
35 | + def __init__(self): | ||
36 | + pass | ||
37 | + | ||
38 | + def SetInput(self, dicom): | ||
39 | + reader = vtkgdcm.vtkGDCMImageReader() | ||
40 | + reader.SetFileName(dicom.image.file) | ||
41 | + imagedata = reader.GetOutput() | ||
42 | + | ||
43 | + scale = imagedata.GetScalarRange() | ||
44 | + | ||
45 | + cast = vtk.vtkImageMapToWindowLevelColors() | ||
46 | + cast.SetInput(imagedata) | ||
47 | + cast.SetWindow(float(dicom.image.window)) | ||
48 | + cast.SetLevel(float(dicom.image.level)) | ||
49 | + | ||
50 | + self.imagedata = cast.GetOutput() | ||
51 | + | ||
52 | + def GetOutput(self): | ||
53 | + return self.imagedata | ||
54 | + | ||
34 | 55 | ||
35 | class DicomLoader(object): | 56 | class DicomLoader(object): |
36 | """ | 57 | """ |
@@ -119,6 +140,15 @@ class Preview(wx.Panel): | @@ -119,6 +140,15 @@ class Preview(wx.Panel): | ||
119 | def SetSubtitle(self, subtitle): | 140 | def SetSubtitle(self, subtitle): |
120 | self.subtitle.SetLabel(subtitle) | 141 | self.subtitle.SetLabel(subtitle) |
121 | 142 | ||
143 | + def SetGroup(self, group): | ||
144 | + self.SetTitle(group.title) | ||
145 | + self.SetSubtitle("%d images"%(group.nslices)) | ||
146 | + d = DicomImageData() | ||
147 | + d.SetInput(group.dicom) | ||
148 | + imagedata = d.GetOutput() | ||
149 | + self.actor.SetInput(imagedata) | ||
150 | + self.render.ResetCamera() | ||
151 | + | ||
122 | def SetImage(self, image_data): | 152 | def SetImage(self, image_data): |
123 | """ | 153 | """ |
124 | Set a Image to preview. | 154 | Set a Image to preview. |
@@ -198,23 +228,23 @@ class DicomPreviewSeries(wx.Panel): | @@ -198,23 +228,23 @@ class DicomPreviewSeries(wx.Panel): | ||
198 | "%d Images" % len(self.series[i][0]), # Subtitle | 228 | "%d Images" % len(self.series[i][0]), # Subtitle |
199 | i) for n, i in enumerate(self.series)] | 229 | i) for n, i in enumerate(self.series)] |
200 | 230 | ||
201 | - def SetDicomSeries(self, files): | ||
202 | - self.files = files | ||
203 | - scroll_range = len(files)/5 | ||
204 | - if scroll_range * 5 < len(files): | 231 | + def SetDicomSeries(self, patient): |
232 | + #self.files = files | ||
233 | + ngroups = patient.ngroups | ||
234 | + self.groups = patient.GetGroups() | ||
235 | + | ||
236 | + scroll_range = ngroups/5 | ||
237 | + if scroll_range * 5 < ngroups: | ||
205 | scroll_range +=1 | 238 | scroll_range +=1 |
206 | self.scroll.SetScrollbar(0, 3, scroll_range, 5) | 239 | self.scroll.SetScrollbar(0, 3, scroll_range, 5) |
207 | self._display_previews() | 240 | self._display_previews() |
208 | 241 | ||
209 | def _display_previews(self): | 242 | def _display_previews(self): |
210 | - initial = self.displayed_position * 5 | ||
211 | - final = initial + 15 | ||
212 | - for f, p in zip(self.files[initial:final], self.previews): | ||
213 | - print "--------" | ||
214 | - print "f:", f | ||
215 | - print "p: ", p | ||
216 | - p.SetImage(f) | ||
217 | - p.Show() | 243 | + begin = self.displayed_position * 5 |
244 | + end = begin + 15 | ||
245 | + for group, preview in zip(self.groups[begin:end], self.previews): | ||
246 | + preview.SetGroup(group) | ||
247 | + preview.Show() | ||
218 | 248 | ||
219 | def OnScroll(self, evt): | 249 | def OnScroll(self, evt): |
220 | self.displayed_position = evt.GetPosition() | 250 | self.displayed_position = evt.GetPosition() |
invesalius/gui/frame.py
@@ -80,6 +80,11 @@ class Frame(wx.Frame): | @@ -80,6 +80,11 @@ class Frame(wx.Frame): | ||
80 | ps.Publisher().subscribe(self.UpdateAui, "Update AUI") | 80 | ps.Publisher().subscribe(self.UpdateAui, "Update AUI") |
81 | ps.Publisher().subscribe(self.ShowTask, 'Show task panel') | 81 | ps.Publisher().subscribe(self.ShowTask, 'Show task panel') |
82 | ps.Publisher().subscribe(self.HideTask, 'Hide task panel') | 82 | ps.Publisher().subscribe(self.HideTask, 'Hide task panel') |
83 | + ps.Publisher().subscribe(self.SetProjectName, 'Set project name') | ||
84 | + | ||
85 | + def SetProjectName(self, pubsub_evt): | ||
86 | + proj_name = pubsub_evt.data | ||
87 | + self.SetTitle("InVesalius 3 - %s"%(proj_name)) | ||
83 | 88 | ||
84 | def UpdateAui(self, pubsub_evt): | 89 | def UpdateAui(self, pubsub_evt): |
85 | self.aui_manager.Update() | 90 | self.aui_manager.Update() |
@@ -169,7 +174,9 @@ class Frame(wx.Frame): | @@ -169,7 +174,9 @@ class Frame(wx.Frame): | ||
169 | 174 | ||
170 | def ShowContentPanel(self, evt_pubsub): | 175 | def ShowContentPanel(self, evt_pubsub): |
171 | aui_manager = self.aui_manager | 176 | aui_manager = self.aui_manager |
177 | + aui_manager.GetPane("Import").Show(0) | ||
172 | aui_manager.GetPane("Data").Show(1) | 178 | aui_manager.GetPane("Data").Show(1) |
179 | + aui_manager.GetPane("Tasks").Show(1) | ||
173 | aui_manager.Update() | 180 | aui_manager.Update() |
174 | 181 | ||
175 | def OnSize(self, evt): | 182 | def OnSize(self, evt): |
invesalius/gui/import_panel.py
@@ -130,21 +130,22 @@ class TextPanel(wx.Panel): | @@ -130,21 +130,22 @@ class TextPanel(wx.Panel): | ||
130 | 130 | ||
131 | tree.Expand(self.root) | 131 | tree.Expand(self.root) |
132 | 132 | ||
133 | - tree.GetMainWindow().Bind(wx.EVT_RIGHT_UP, self.OnRightUp) | ||
134 | tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivate) | 133 | tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivate) |
135 | 134 | ||
136 | def OnActivate(self, evt): | 135 | def OnActivate(self, evt): |
137 | print "OnActivate" | 136 | print "OnActivate" |
138 | item = evt.GetItem() | 137 | item = evt.GetItem() |
139 | - print self.tree.GetItemPyData(item) | ||
140 | - | ||
141 | - | ||
142 | - def OnRightUp(self, evt): | ||
143 | - pos = evt.GetPosition() | ||
144 | - item, flags, col = self.tree.HitTest(pos) | ||
145 | - if item: | ||
146 | - print 'Flags: %s, Col:%s, Text: %s' %\ | ||
147 | - (flags, col, self.tree.GetItemText(item, col)) | 138 | + group = self.tree.GetItemPyData(item) |
139 | + if group: | ||
140 | + print "send" | ||
141 | + ps.Publisher().sendMessage('Open DICOM group', | ||
142 | + group) | ||
143 | + | ||
144 | + else: | ||
145 | + if self.tree.IsExpanded(item): | ||
146 | + self.tree.Collapse(item) | ||
147 | + else: | ||
148 | + self.tree.Expand(item) | ||
148 | 149 | ||
149 | def OnSize(self, evt): | 150 | def OnSize(self, evt): |
150 | self.tree.SetSize(self.GetSize()) | 151 | self.tree.SetSize(self.GetSize()) |
invesalius/reader/dicom_grouper.py
@@ -51,6 +51,8 @@ | @@ -51,6 +51,8 @@ | ||
51 | # <dicom.image.number> and <dicom.acquisition.series_number> | 51 | # <dicom.image.number> and <dicom.acquisition.series_number> |
52 | # were swapped | 52 | # were swapped |
53 | 53 | ||
54 | +import gdcm | ||
55 | + | ||
54 | ORIENT_MAP = {"SAGITTAL":0, "CORONAL":1, "AXIAL":2, "OBLIQUE":2} | 56 | ORIENT_MAP = {"SAGITTAL":0, "CORONAL":1, "AXIAL":2, "OBLIQUE":2} |
55 | 57 | ||
56 | 58 | ||
@@ -96,7 +98,28 @@ class DicomGroup: | @@ -96,7 +98,28 @@ class DicomGroup: | ||
96 | # (interpolated) | 98 | # (interpolated) |
97 | return self.slices_dict.values() | 99 | return self.slices_dict.values() |
98 | 100 | ||
99 | - def GetSortedList(self): | 101 | + def GetFilenameList(self): |
102 | + # Should be called when user selects this group | ||
103 | + # This list will be used to create the vtkImageData | ||
104 | + # (interpolated) | ||
105 | + | ||
106 | + filelist = [dicom.image.file for dicom in | ||
107 | + self.slices_dict.values()] | ||
108 | + | ||
109 | + # Sort slices using GDCM | ||
110 | + if (self.dicom.image.orientation_label <> "CORONAL"): | ||
111 | + #Organize reversed image | ||
112 | + sorter = gdcm.IPPSorter() | ||
113 | + sorter.SetComputeZSpacing(True) | ||
114 | + sorter.SetZSpacingTolerance(1e-10) | ||
115 | + sorter.Sort(filelist) | ||
116 | + filelist = sorter.GetFilenames() | ||
117 | + | ||
118 | + #Getting organized image | ||
119 | + return filelist | ||
120 | + | ||
121 | + | ||
122 | + def GetHandSortedList(self): | ||
100 | # This will be used to fix problem 1, after merging | 123 | # This will be used to fix problem 1, after merging |
101 | # single DicomGroups of same study_id and orientation | 124 | # single DicomGroups of same study_id and orientation |
102 | list_ = self.slices_dict.values() | 125 | list_ = self.slices_dict.values() |
@@ -106,7 +129,7 @@ class DicomGroup: | @@ -106,7 +129,7 @@ class DicomGroup: | ||
106 | return list_ | 129 | return list_ |
107 | 130 | ||
108 | def UpdateZSpacing(self): | 131 | def UpdateZSpacing(self): |
109 | - list_ = self.GetSortedList() | 132 | + list_ = self.GetHandSortedList() |
110 | 133 | ||
111 | if (len(list_) > 1): | 134 | if (len(list_) > 1): |
112 | dicom = list_[0] | 135 | dicom = list_[0] |
@@ -246,7 +269,7 @@ class PatientGroup: | @@ -246,7 +269,7 @@ class PatientGroup: | ||
246 | group_counter = 0 | 269 | group_counter = 0 |
247 | for group_key in dict_to_change: | 270 | for group_key in dict_to_change: |
248 | # 2nd STEP: SORT | 271 | # 2nd STEP: SORT |
249 | - sorted_list = dict_to_change[group_key].GetSortedList() | 272 | + sorted_list = dict_to_change[group_key].GetHandSortedList() |
250 | 273 | ||
251 | # 3rd STEP: CHECK DIFFERENCES | 274 | # 3rd STEP: CHECK DIFFERENCES |
252 | axis = ORIENT_MAP[group_key[0]] # based on orientation | 275 | axis = ORIENT_MAP[group_key[0]] # based on orientation |
invesalius/reader/dicom_reader.py
@@ -28,32 +28,26 @@ import dicom | @@ -28,32 +28,26 @@ import dicom | ||
28 | import dicom_grouper | 28 | import dicom_grouper |
29 | import data.imagedata_utils as iu | 29 | import data.imagedata_utils as iu |
30 | 30 | ||
31 | -def LoadImages(dir_): | 31 | +def ReadDicomGroup(dir_): |
32 | 32 | ||
33 | patient_group = GetDicomGroups(dir_) | 33 | patient_group = GetDicomGroups(dir_) |
34 | - filelist, dicom, zspacing = SelectLargerDicomGroup(patient_group) | ||
35 | - filelist = SortFiles(filelist, dicom) | ||
36 | - imagedata = CreateImageData(filelist, zspacing) | ||
37 | - | ||
38 | - return imagedata, dicom | 34 | + if len(patient_group) > 0: |
35 | + filelist, dicom, zspacing = SelectLargerDicomGroup(patient_group) | ||
36 | + filelist = SortFiles(filelist, dicom) | ||
37 | + imagedata = CreateImageData(filelist, zspacing) | ||
38 | + return imagedata, dicom | ||
39 | + else: | ||
40 | + return False | ||
39 | 41 | ||
40 | 42 | ||
41 | def SelectLargerDicomGroup(patient_group): | 43 | def SelectLargerDicomGroup(patient_group): |
42 | - nslices_old = 0 | 44 | + maxslices = 0 |
43 | for patient in patient_group: | 45 | for patient in patient_group: |
44 | group_list = patient.GetGroups() | 46 | group_list = patient.GetGroups() |
45 | for group in group_list: | 47 | for group in group_list: |
46 | - nslices = group.nslices | ||
47 | - print "nslices:", nslices | ||
48 | - if (nslices >= nslices_old): | ||
49 | - dicoms = group.GetList() | ||
50 | - zspacing = group.zspacing | ||
51 | - nslices_old = nslices | ||
52 | - | ||
53 | - filelist = [] | ||
54 | - for dicom in dicoms: | ||
55 | - filelist.append(dicom.image.file) | ||
56 | - return filelist, dicom, zspacing | 48 | + if group.nslices > maxslices: |
49 | + larger_group = group | ||
50 | + return larger_group | ||
57 | 51 | ||
58 | def SortFiles(filelist, dicom): | 52 | def SortFiles(filelist, dicom): |
59 | # Sort slices | 53 | # Sort slices |
@@ -71,53 +65,6 @@ def SortFiles(filelist, dicom): | @@ -71,53 +65,6 @@ def SortFiles(filelist, dicom): | ||
71 | return filelist | 65 | return filelist |
72 | 66 | ||
73 | 67 | ||
74 | -def CreateImageData(filelist, zspacing): | ||
75 | - | ||
76 | - if not(const.REDUCE_IMAGEDATA_QUALITY): | ||
77 | - array = vtk.vtkStringArray() | ||
78 | - for x in xrange(len(filelist)): | ||
79 | - array.InsertValue(x,filelist[x]) | ||
80 | - | ||
81 | - reader = vtkgdcm.vtkGDCMImageReader() | ||
82 | - reader.SetFileNames(array) | ||
83 | - reader.Update() | ||
84 | - | ||
85 | - # The zpacing is a DicomGroup property, so we need to set it | ||
86 | - imagedata = vtk.vtkImageData() | ||
87 | - imagedata.DeepCopy(reader.GetOutput()) | ||
88 | - spacing = imagedata.GetSpacing() | ||
89 | - imagedata.SetSpacing(spacing[0], spacing[1], zspacing) | ||
90 | - else: | ||
91 | - # Reformat each slice and future append them | ||
92 | - appender = vtk.vtkImageAppend() | ||
93 | - appender.SetAppendAxis(2) #Define Stack in Z | ||
94 | - | ||
95 | - # Reformat each slice | ||
96 | - for x in xrange(len(filelist)): | ||
97 | - # TODO: We need to check this automatically according | ||
98 | - # to each computer's architecture | ||
99 | - # If the resolution of the matrix is too large | ||
100 | - reader = vtkgdcm.vtkGDCMImageReader() | ||
101 | - reader.SetFileName(filelist[x]) | ||
102 | - reader.Update() | ||
103 | - | ||
104 | - #Resample image in x,y dimension | ||
105 | - slice_imagedata = iu.ResampleImage2D(reader.GetOutput(), 256) | ||
106 | - | ||
107 | - #Stack images in Z axes | ||
108 | - appender.AddInput(slice_imagedata) | ||
109 | - appender.Update() | ||
110 | - | ||
111 | - # The zpacing is a DicomGroup property, so we need to set it | ||
112 | - imagedata = vtk.vtkImageData() | ||
113 | - imagedata.DeepCopy(appender.GetOutput()) | ||
114 | - spacing = imagedata.GetSpacing() | ||
115 | - | ||
116 | - imagedata.SetSpacing(spacing[0], spacing[1], zspacing) | ||
117 | - | ||
118 | - imagedata.Update() | ||
119 | - return imagedata | ||
120 | - | ||
121 | 68 | ||
122 | def GetDicomGroups(directory, recursive=True): | 69 | def GetDicomGroups(directory, recursive=True): |
123 | """ | 70 | """ |