Commit f7a5655a4a0ea49900ba20f7ecef1926b2bf70c5

Authored by tfmoraes
1 parent ff5ac193

ENH: Handle sagittal and coronal images.

* Handling sagittal and coronal (not tested) images. Sagittal and coronal
 images are stored in memmap matrix as axial doing insertion acording to
 orientation;
* Axial, sagittal and coronal are showed in its correspondent plane.
invesalius/control.py
... ... @@ -357,7 +357,7 @@ class Controller():
357 357 ps.Publisher().sendMessage('Load slice to viewer',
358 358 (proj.imagedata,
359 359 proj.mask_dict))
360   - ps.Publisher().sendMessage('Load slice plane')
  360 + #ps.Publisher().sendMessage('Load slice plane')
361 361 ps.Publisher().sendMessage('Bright and contrast adjustment image',\
362 362 (proj.window, proj.level))
363 363 ps.Publisher().sendMessage('Update window level value',\
... ... @@ -409,7 +409,7 @@ class Controller():
409 409 name_to_const[dicom.image.orientation_label]
410 410 proj.window = float(dicom.image.window)
411 411 proj.level = float(dicom.image.level)
412   - proj.threshold_range = imagedata.GetScalarRange()
  412 + proj.threshold_range = (-1024, 3033)
413 413  
414 414  
415 415 ######
... ... @@ -445,14 +445,17 @@ class Controller():
445 445 bits = dicom.image.bits_allocad
446 446 sop_class_uid = dicom.acquisition.sop_class_uid
447 447 xyspacing = dicom.image.spacing
  448 + orientation = dicom.image.orientation_label
448 449  
449 450 if sop_class_uid == '1.2.840.10008.5.1.4.1.1.7': #Secondary Capture Image Storage
450 451 use_dcmspacing = 1
451 452 else:
452 453 use_dcmspacing = 0
453 454  
454   - imagedata = utils.CreateImageData(filelist, zspacing, xyspacing,size,
455   - bits, use_dcmspacing)
  455 + #imagedata = utils.CreateImageData(filelist, zspacing, xyspacing,size,
  456 + #bits, use_dcmspacing)
  457 +
  458 + imagedata = None
456 459  
457 460 # 1(a): Fix gantry tilt, if any
458 461 tilt_value = dicom.acquisition.tilt
... ... @@ -466,10 +469,23 @@ class Controller():
466 469 tilt_value = -1*tilt_value
467 470 imagedata = utils.FixGantryTilt(imagedata, tilt_value)
468 471  
469   - self.matrix, self.filename = utils.dcm2memmap(filelist, size)
  472 + wl = float(dicom.image.level)
  473 + ww = float(dicom.image.window)
  474 +
  475 + self.matrix, self.filename = utils.dcm2memmap(filelist, size,
  476 + orientation)
470 477 self.Slice = sl.Slice()
471 478 self.Slice.matrix = self.matrix
472   - self.Slice.spacing = xyspacing[0], xyspacing[1], zspacing
  479 +
  480 + if orientation == 'AXIAL':
  481 + self.Slice.spacing = xyspacing[0], xyspacing[1], zspacing
  482 + elif orientation == 'CORONAL':
  483 + self.Slice.spacing = xyspacing[0], zspacing, xyspacing[1]
  484 + elif orientation == 'SAGITTAL':
  485 + self.Slice.spacing = zspacing, xyspacing[1], xyspacing[0]
  486 +
  487 + self.Slice.window_level = wl
  488 + self.Slice.window_width = ww
473 489 return imagedata, dicom
474 490  
475 491 def LoadImagedataInfo(self):
... ...
invesalius/data/imagedata_utils.py
... ... @@ -456,13 +456,19 @@ class ImageCreator:
456 456  
457 457 return imagedata
458 458  
459   -def dcm2memmap(files, slice_size):
  459 +def dcm2memmap(files, slice_size, orientation):
460 460 """
461 461 From a list of dicom files it creates memmap file in the temp folder and
462 462 returns it and its related filename.
463 463 """
464 464 temp_file = tempfile.mktemp()
465   - shape = len(files), slice_size[1], slice_size[0]
  465 +
  466 + if orientation == 'SAGITTAL':
  467 + shape = slice_size[0], slice_size[1], len(files)
  468 + elif orientation == 'CORONAL':
  469 + shape = slice_size[1], len(files), slice_size[0]
  470 + else:
  471 + shape = len(files), slice_size[1], slice_size[0]
466 472  
467 473 matrix = numpy.memmap(temp_file, mode='w+', dtype='int16', shape=shape)
468 474 dcm_reader = vtkgdcm.vtkGDCMImageReader()
... ... @@ -471,25 +477,43 @@ def dcm2memmap(files, slice_size):
471 477 dcm_reader.Update()
472 478 image = dcm_reader.GetOutput()
473 479 array = numpy_support.vtk_to_numpy(image.GetPointData().GetScalars())
474   - array.shape = matrix.shape[1], matrix.shape[2]
475   - matrix[n] = array
  480 + if orientation == 'CORONAL':
  481 + array.shape = matrix.shape[0], matrix.shape[2]
  482 + matrix[:, n, :] = array
  483 + elif orientation == 'SAGITTAL':
  484 + array.shape = matrix.shape[0], matrix.shape[1]
  485 + matrix[:, :, n] = array
  486 + else:
  487 + array.shape = matrix.shape[1], matrix.shape[2]
  488 + matrix[n] = array
476 489  
477 490 matrix.flush()
478 491 return matrix, temp_file
479 492  
480   -def to_vtk(n_array, spacing):
  493 +def to_vtk(n_array, spacing, slice_number, orientation):
481 494 dy, dx = n_array.shape
482 495 n_array.shape = dx * dy
483 496  
484 497 v_image = numpy_support.numpy_to_vtk(n_array)
485 498  
  499 + print orientation
  500 + if orientation == 'AXIAL':
  501 + dz = 1
  502 + extent = (0, dx -1, 0, dy -1, slice_number, slice_number)
  503 + elif orientation == 'SAGITAL':
  504 + dx, dy, dz = 1, dx, dy
  505 + extent = (slice_number, slice_number, 0, dy - 1, 0, dz - 1)
  506 + elif orientation == 'CORONAL':
  507 + dx, dy, dz = dx, 1, dy
  508 + extent = (0, dx - 1, slice_number, slice_number, 0, dz - 1)
  509 +
486 510 # Generating the vtkImageData
487 511 image = vtk.vtkImageData()
488   - image.SetDimensions(dx, dy, 1)
489 512 image.SetOrigin(0, 0, 0)
490 513 image.SetSpacing(spacing)
491 514 image.SetNumberOfScalarComponents(1)
492   - image.SetExtent(0, dx -1, 0, dy -1, 0, 0)
  515 + image.SetDimensions(dx, dy, dz)
  516 + image.SetExtent(extent)
493 517 image.SetScalarType(numpy_support.get_vtk_array_type(n_array.dtype))
494 518 image.AllocateScalars()
495 519 image.GetPointData().SetScalars(v_image)
... ...
invesalius/data/slice_.py
... ... @@ -239,15 +239,11 @@ class Slice(object):
239 239 def GetSlices(self, orientation, slice_number):
240 240 if orientation == 'AXIAL':
241 241 n_array = numpy.array(self.matrix[slice_number])
242   - spacing = self.spacing
243 242 elif orientation == 'CORONAL':
244 243 n_array = numpy.array(self.matrix[..., slice_number, ...])
245   - spacing = self.spacing[0], self.spacing[2], self.spacing[1]
246 244 elif orientation == 'SAGITAL':
247 245 n_array = numpy.array(self.matrix[..., ..., slice_number])
248   - spacing = self.spacing[1], self.spacing[2], self.spacing[0]
249   -
250   - image = iu.to_vtk(n_array, spacing)
  246 + image = iu.to_vtk(n_array, self.spacing, slice_number, orientation)
251 247 image = self.do_ww_wl(image)
252 248 return image
253 249  
... ... @@ -619,11 +615,13 @@ class Slice(object):
619 615 ps.Publisher().sendMessage('Update slice viewer')
620 616  
621 617 def do_ww_wl(self, image):
  618 + print self.window_width, self.window_level
  619 + print image.GetScalarRange()
622 620 colorer = vtk.vtkImageMapToWindowLevelColors()
623 621 colorer.SetInput(image)
624   - colorer.SetWindow(255)
625   - colorer.SetLevel(127)
626   - colorer.SetOutputFormatToRGBA()
  622 + colorer.SetWindow(self.window_width)
  623 + colorer.SetLevel(self.window_level)
  624 + colorer.SetOutputFormatToRGB()
627 625 colorer.Update()
628 626  
629 627 return colorer.GetOutput()
... ...
invesalius/data/viewer_slice.py
... ... @@ -173,7 +173,6 @@ class Viewer(wx.Panel):
173 173 self.cam = ren.GetActiveCamera()
174 174 self.ren = ren
175 175  
176   -
177 176 def SetInteractorStyle(self, state):
178 177 self.state = state
179 178 action = {const.SLICE_STATE_CROSS:
... ... @@ -1056,26 +1055,26 @@ class Viewer(wx.Panel):
1056 1055 return cursor
1057 1056  
1058 1057 def SetInput(self, imagedata, mask_dict):
1059   - pass
1060   - #self.imagedata = imagedata
  1058 + self.slice_ = sl.Slice()
1061 1059  
1062   - ##ren = self.ren
1063   - #interactor = self.interactor
  1060 + max_slice_number = sl.Slice().GetNumberOfSlices(self.orientation)
  1061 + self.scroll.SetScrollbar(wx.SB_VERTICAL, 1, max_slice_number,
  1062 + max_slice_number)
1064 1063  
1065   - ## Slice pipeline, to be inserted into current viewer
1066   - #slice_ = sl.Slice()
  1064 + self.actor = vtk.vtkImageActor()
  1065 + self.ren.AddActor(self.actor)
  1066 + self.set_slice_number(0)
  1067 + self.__update_camera()
  1068 + self.ren.ResetCamera()
1067 1069 #if slice_.imagedata is None:
1068 1070 #slice_.SetInput(imagedata, mask_dict)
1069 1071  
1070   - actor = vtk.vtkImageActor()
1071 1072 ##actor.SetInput(slice_.GetOutput())
1072 1073 #self.LoadRenderers(slice_.GetOutput())
1073 1074 #self.__configure_renderers()
1074 1075 #ren = self.slice_data_list[0].renderer
1075 1076 #actor = self.slice_data_list[0].actor
1076 1077 #actor_bound = actor.GetBounds()
1077   - self.actor = actor
1078   - self.ren.AddActor(self.actor)
1079 1078 #self.cam = ren.GetActiveCamera()
1080 1079  
1081 1080 #for slice_data in self.slice_data_list:
... ... @@ -1088,12 +1087,10 @@ class Viewer(wx.Panel):
1088 1087  
1089 1088 #if actor.GetSliceNumberMax() % number_of_slices:
1090 1089 #max_slice_number += 1
1091   - max_slice_number = sl.Slice().GetNumberOfSlices(self.orientation)
1092   - self.scroll.SetScrollbar(wx.SB_VERTICAL, 1, max_slice_number,
1093   - max_slice_number)
1094 1090 #self.set_scroll_position(0)
1095 1091  
1096 1092 #actor_bound = actor.GetBounds()
  1093 + self.interactor.Render()
1097 1094  
1098 1095 #self.EnableText()
1099 1096 ## Insert cursor
... ... @@ -1268,43 +1265,23 @@ class Viewer(wx.Panel):
1268 1265 renderer.AddViewProp(slice_data.box_actor)
1269 1266 return slice_data
1270 1267  
1271   - def __update_camera(self, slice_data):
  1268 + def __update_camera(self):
1272 1269 orientation = self.orientation
1273 1270 proj = project.Project()
1274   - orig_orien = proj.original_orientation
  1271 + orig_orien = 1 #proj.original_orientation
1275 1272  
1276   - cam = slice_data.renderer.GetActiveCamera()
1277   - cam.SetFocalPoint(0, 0, 0)
1278   - cam.SetViewUp(const.SLICE_POSITION[orig_orien][0][self.orientation])
1279   - cam.SetPosition(const.SLICE_POSITION[orig_orien][1][self.orientation])
1280   - cam.ComputeViewPlaneNormal()
1281   - cam.OrthogonalizeViewUp()
1282   - cam.ParallelProjectionOn()
1283   -
1284   - self.__update_display_extent(slice_data)
  1273 + self.cam.SetFocalPoint(0, 0, 0)
  1274 + self.cam.SetViewUp(const.SLICE_POSITION[orig_orien][0][self.orientation])
  1275 + self.cam.SetPosition(const.SLICE_POSITION[orig_orien][1][self.orientation])
  1276 + self.cam.ComputeViewPlaneNormal()
  1277 + self.cam.OrthogonalizeViewUp()
  1278 + self.cam.ParallelProjectionOn()
1285 1279  
1286   - slice_data.renderer.ResetCamera()
1287 1280 #slice_data.renderer.Render()
1288 1281  
1289   - def __update_display_extent(self, slice_data):
1290   - e = self.imagedata.GetWholeExtent()
1291   - proj = project.Project()
1292   -
1293   - pos = slice_data.number
1294   -
1295   - x = (pos, pos, e[2], e[3], e[4], e[5])
1296   - y = (e[0], e[1], pos, pos, e[4], e[5])
1297   - z = (e[0], e[1], e[2], e[3], pos, pos)
1298   -
1299   - if (proj.original_orientation == const.AXIAL):
1300   - new_extent = {"SAGITAL": x, "CORONAL": y, "AXIAL": z}
1301   - elif(proj.original_orientation == const.SAGITAL):
1302   - new_extent = {"SAGITAL": z,"CORONAL": x,"AXIAL": y}
1303   - elif(proj.original_orientation == const.CORONAL):
1304   - new_extent = {"SAGITAL": x,"CORONAL": z,"AXIAL": y}
1305   -
1306   - slice_data.actor.SetDisplayExtent(new_extent[self.orientation])
1307   - slice_data.renderer.ResetCameraClippingRange()
  1282 + def __update_display_extent(self, image):
  1283 + self.actor.SetDisplayExtent(image.GetExtent())
  1284 + self.ren.ResetCameraClippingRange()
1308 1285  
1309 1286 def UpdateRender(self, evt):
1310 1287 self.interactor.Render()
... ... @@ -1341,18 +1318,10 @@ class Viewer(wx.Panel):
1341 1318  
1342 1319 def OnScrollBar(self, evt=None):
1343 1320 pos = self.scroll.GetThumbPosition()
1344   - slice_ = sl.Slice()
1345   - image = slice_.GetSlices(self.orientation, pos)
1346   - self.actor.SetInput(image)
1347   - self.ren.ResetCamera()
  1321 + self.set_slice_number(pos)
1348 1322 self.interactor.Render()
1349   - print "slice", pos
1350   - #self.set_slice_number(pos)
1351   - ##self.UpdateSlice3D(pos)
1352   - #self.pos = pos
1353   - #self.interactor.Render()
1354   - #if evt:
1355   - #evt.Skip()
  1323 + if evt:
  1324 + evt.Skip()
1356 1325  
1357 1326 def OnScrollBarRelease(self, evt):
1358 1327 #self.UpdateSlice3D(self.pos)
... ... @@ -1409,43 +1378,14 @@ class Viewer(wx.Panel):
1409 1378 evt.Skip()
1410 1379  
1411 1380 def set_slice_number(self, index):
1412   - self.slice_number = index
1413   - # for m in self.actors_by_slice_number.values():
1414   - # for actor in m:
1415   - # actor.SetVisibility(0)
1416   - # Removing actor from the previous renderers/slice.
1417   - for n in self.renderers_by_slice_number:
1418   - renderer = self.renderers_by_slice_number[n]
1419   - for actor in self.actors_by_slice_number.get(n, []):
1420   - renderer.RemoveActor(actor)
1421   -
1422   - self.renderers_by_slice_number = {}
1423   -
1424   - for n, slice_data in enumerate(self.slice_data_list):
1425   - ren = slice_data.renderer
1426   - actor = slice_data.actor
1427   - pos = self.layout[0] * self.layout[1] * index + n
1428   - max = actor.GetSliceNumberMax() + 1
1429   - if pos < max:
1430   - self.renderers_by_slice_number[pos] = ren
1431   - for m_actor in self.actors_by_slice_number.get(pos, []):
1432   - ren.AddActor(m_actor)
1433   - slice_data.SetNumber(pos)
1434   - # for actor in self.actors_by_slice_number.get(pos, []):
1435   - # actor.SetVisibility(1)
1436   - self.__update_display_extent(slice_data)
1437   - slice_data.Show()
1438   - else:
1439   - slice_data.Hide()
1440   -
1441   - position = {"SAGITAL": {0: slice_data.number},
1442   - "CORONAL": {1: slice_data.number},
1443   - "AXIAL": {2: slice_data.number}}
1444   -
1445   - #if 'DEFAULT' in self.modes:
1446   - # ps.Publisher().sendMessage(
1447   - # 'Update cursor single position in slice',
1448   - # position[self.orientation])
  1381 + image = self.slice_.GetSlices(self.orientation, index)
  1382 + self.actor.SetInput(image)
  1383 + self.__update_display_extent(image)
  1384 + print "slice", index
  1385 + print "display extent", self.actor.GetDisplayExtent()
  1386 + print "whole extent", image.GetWholeExtent()
  1387 + print "boundsa", self.actor.GetBounds()
  1388 + print "camera", self.cam.GetPosition(), self.cam.GetFocalPoint()
1449 1389  
1450 1390 def ChangeSliceNumber(self, pubsub_evt):
1451 1391 index = pubsub_evt.data
... ...