Commit 87bb8b913bd958cd13016dc921c46d39ce44ca5e

Authored by Renan
2 parents 392671f2 9823122a
Exists in master

Merge branch 'master' into multimodal_tracking

# Conflicts:
#	invesalius/gui/task_navigator.py
invesalius/constants.py
@@ -828,7 +828,7 @@ TREKKER_CONFIG = {'seed_max': 1, 'step_size': 0.1, 'min_fod': 0.1, 'probe_qualit @@ -828,7 +828,7 @@ TREKKER_CONFIG = {'seed_max': 1, 'step_size': 0.1, 'min_fod': 0.1, 'probe_qualit
828 'write_interval': 50, 'numb_threads': '', 'max_lenth': 200, 828 'write_interval': 50, 'numb_threads': '', 'max_lenth': 200,
829 'min_lenth': 20, 'max_sampling_step': 100} 829 'min_lenth': 20, 'max_sampling_step': 100}
830 830
831 -MARKER_FILE_MAGICK_STRING = "INVESALIUS3_MARKER_FILE_" 831 +MARKER_FILE_MAGICK_STRING = "##INVESALIUS3_MARKER_FILE_"
832 CURRENT_MARKER_FILE_VERSION = 0 832 CURRENT_MARKER_FILE_VERSION = 0
833 WILDCARD_MARKER_FILES = _("Marker scanner coord files (*.mkss)|*.mkss") 833 WILDCARD_MARKER_FILES = _("Marker scanner coord files (*.mkss)|*.mkss")
834 834
invesalius/control.py
@@ -122,8 +122,6 @@ class Controller(): @@ -122,8 +122,6 @@ class Controller():
122 122
123 Publisher.subscribe(self.OnSaveProject, 'Save project') 123 Publisher.subscribe(self.OnSaveProject, 'Save project')
124 124
125 - Publisher.subscribe(self.Send_affine, 'Get affine matrix')  
126 -  
127 Publisher.subscribe(self.create_project_from_matrix, 'Create project from matrix') 125 Publisher.subscribe(self.create_project_from_matrix, 'Create project from matrix')
128 126
129 Publisher.subscribe(self.show_mask_preview, 'Show mask preview') 127 Publisher.subscribe(self.show_mask_preview, 'Show mask preview')
@@ -506,8 +504,9 @@ class Controller(): @@ -506,8 +504,9 @@ class Controller():
506 utils.debug("No medical images found on given directory") 504 utils.debug("No medical images found on given directory")
507 return 505 return
508 506
509 - matrix, matrix_filename = self.OpenOtherFiles(group)  
510 - self.CreateOtherProject(str(name[0]), matrix, matrix_filename) 507 + if group:
  508 + matrix, matrix_filename = self.OpenOtherFiles(group)
  509 + self.CreateOtherProject(str(name[0]), matrix, matrix_filename)
511 # OPTION 4: Nothing... 510 # OPTION 4: Nothing...
512 511
513 self.LoadProject() 512 self.LoadProject()
@@ -623,6 +622,11 @@ class Controller(): @@ -623,6 +622,11 @@ class Controller():
623 Publisher.sendMessage(('Set scroll position', 'AXIAL'), index=proj.matrix_shape[0]/2) 622 Publisher.sendMessage(('Set scroll position', 'AXIAL'), index=proj.matrix_shape[0]/2)
624 Publisher.sendMessage(('Set scroll position', 'SAGITAL'),index=proj.matrix_shape[1]/2) 623 Publisher.sendMessage(('Set scroll position', 'SAGITAL'),index=proj.matrix_shape[1]/2)
625 Publisher.sendMessage(('Set scroll position', 'CORONAL'),index=proj.matrix_shape[2]/2) 624 Publisher.sendMessage(('Set scroll position', 'CORONAL'),index=proj.matrix_shape[2]/2)
  625 +
  626 + if self.Slice.affine is not None:
  627 + Publisher.sendMessage('Enable Go-to-Coord', status=True)
  628 + else:
  629 + Publisher.sendMessage('Enable Go-to-Coord', status=False)
626 630
627 Publisher.sendMessage('End busy cursor') 631 Publisher.sendMessage('End busy cursor')
628 632
@@ -715,9 +719,6 @@ class Controller(): @@ -715,9 +719,6 @@ class Controller():
715 proj.matrix_dtype = matrix.dtype.name 719 proj.matrix_dtype = matrix.dtype.name
716 proj.matrix_filename = matrix_filename 720 proj.matrix_filename = matrix_filename
717 721
718 - if self.affine is not None:  
719 - proj.affine = self.affine.tolist()  
720 -  
721 # Orientation must be CORONAL in order to as_closes_canonical and 722 # Orientation must be CORONAL in order to as_closes_canonical and
722 # swap axis in img2memmap to work in a standardized way. 723 # swap axis in img2memmap to work in a standardized way.
723 # TODO: Create standard import image for all acquisition orientations 724 # TODO: Create standard import image for all acquisition orientations
@@ -730,6 +731,8 @@ class Controller(): @@ -730,6 +731,8 @@ class Controller():
730 proj.level = self.Slice.window_level 731 proj.level = self.Slice.window_level
731 proj.threshold_range = int(matrix.min()), int(matrix.max()) 732 proj.threshold_range = int(matrix.min()), int(matrix.max())
732 proj.spacing = self.Slice.spacing 733 proj.spacing = self.Slice.spacing
  734 + if self.Slice.affine is not None:
  735 + proj.affine = self.Slice.affine.tolist()
733 736
734 ###### 737 ######
735 session = ses.Session() 738 session = ses.Session()
@@ -915,16 +918,7 @@ class Controller(): @@ -915,16 +918,7 @@ class Controller():
915 matrix, matrix_filename = self.OpenOtherFiles(group) 918 matrix, matrix_filename = self.OpenOtherFiles(group)
916 self.CreateOtherProject(name, matrix, matrix_filename) 919 self.CreateOtherProject(name, matrix, matrix_filename)
917 self.LoadProject() 920 self.LoadProject()
918 - if group.affine.any():  
919 - # TODO: replace the inverse of the affine by the actual affine in the whole code  
920 - # remove scaling factor for non-unitary voxel dimensions  
921 - # self.affine = image_utils.world2invspace(affine=group.affine)  
922 - scale, shear, angs, trans, persp = tr.decompose_matrix(group.affine)  
923 - self.affine = np.linalg.inv(tr.compose_matrix(scale=None, shear=shear,  
924 - angles=angs, translate=trans, perspective=persp))  
925 - # print("repos_img: {}".format(repos_img))  
926 - self.Slice.affine = self.affine  
927 - Publisher.sendMessage('Update affine matrix', affine=self.affine) 921 +
928 Publisher.sendMessage("Enable state project", state=True) 922 Publisher.sendMessage("Enable state project", state=True)
929 else: 923 else:
930 dialog.ImportInvalidFiles(ftype="Others") 924 dialog.ImportInvalidFiles(ftype="Others")
@@ -1034,13 +1028,7 @@ class Controller(): @@ -1034,13 +1028,7 @@ class Controller():
1034 self.matrix, scalar_range, self.filename = image_utils.img2memmap(group) 1028 self.matrix, scalar_range, self.filename = image_utils.img2memmap(group)
1035 1029
1036 hdr = group.header 1030 hdr = group.header
1037 - # if group.affine.any():  
1038 - # self.affine = group.affine  
1039 - # Publisher.sendMessage('Update affine matrix',  
1040 - # affine=self.affine, status=True)  
1041 hdr.set_data_dtype('int16') 1031 hdr.set_data_dtype('int16')
1042 - dims = hdr.get_zooms()  
1043 - dimsf = tuple([float(s) for s in dims])  
1044 1032
1045 wl = float((scalar_range[0] + scalar_range[1]) * 0.5) 1033 wl = float((scalar_range[0] + scalar_range[1]) * 0.5)
1046 ww = float((scalar_range[1] - scalar_range[0])) 1034 ww = float((scalar_range[1] - scalar_range[0]))
@@ -1048,19 +1036,29 @@ class Controller(): @@ -1048,19 +1036,29 @@ class Controller():
1048 self.Slice = sl.Slice() 1036 self.Slice = sl.Slice()
1049 self.Slice.matrix = self.matrix 1037 self.Slice.matrix = self.matrix
1050 self.Slice.matrix_filename = self.filename 1038 self.Slice.matrix_filename = self.filename
1051 -  
1052 - self.Slice.spacing = dimsf 1039 + # even though the axes 0 and 2 are swapped when creating self.matrix
  1040 + # the spacing should be kept the original, as it is modified somewhere later
  1041 + # otherwise generate wrong results
  1042 + # also need to convert to float because original get_zooms return numpy.float32
  1043 + # which is unsupported by the plist for saving the project
  1044 + self.Slice.spacing = tuple([float(s) for s in hdr.get_zooms()])
1053 self.Slice.window_level = wl 1045 self.Slice.window_level = wl
1054 self.Slice.window_width = ww 1046 self.Slice.window_width = ww
1055 1047
  1048 + if group.affine.any():
  1049 + # remove scaling factor for non-unitary voxel dimensions
  1050 + scale, shear, angs, trans, persp = tr.decompose_matrix(group.affine)
  1051 + self.Slice.affine = np.linalg.inv(tr.compose_matrix(scale=None, shear=shear,
  1052 + angles=angs, translate=trans, perspective=persp))
  1053 + else:
  1054 + self.Slice.affine = None
  1055 +
1056 scalar_range = int(scalar_range[0]), int(scalar_range[1]) 1056 scalar_range = int(scalar_range[0]), int(scalar_range[1])
  1057 +
1057 Publisher.sendMessage('Update threshold limits list', 1058 Publisher.sendMessage('Update threshold limits list',
1058 threshold_range=scalar_range) 1059 threshold_range=scalar_range)
1059 - return self.matrix, self.filename  
1060 1060
1061 - def Send_affine(self):  
1062 - if self.affine is not None:  
1063 - Publisher.sendMessage('Update affine matrix', affine=self.affine) 1061 + return self.matrix, self.filename
1064 1062
1065 def LoadImagedataInfo(self): 1063 def LoadImagedataInfo(self):
1066 proj = prj.Project() 1064 proj = prj.Project()
invesalius/data/imagedata_utils.py
@@ -549,6 +549,17 @@ def get_LUT_value_255(data, window, level): @@ -549,6 +549,17 @@ def get_LUT_value_255(data, window, level):
549 return data 549 return data
550 550
551 551
  552 +def get_LUT_value(data, window, level):
  553 + shape = data.shape
  554 + data_ = data.ravel()
  555 + data = np.piecewise(data_,
  556 + [data_ <= (level - 0.5 - (window-1)/2),
  557 + data_ > (level - 0.5 + (window-1)/2)],
  558 + [0, window, lambda data_: ((data_ - (level - 0.5))/(window-1) + 0.5)*(window)])
  559 + data.shape = shape
  560 + return data
  561 +
  562 +
552 def image_normalize(image, min_=0.0, max_=1.0, output_dtype=np.int16): 563 def image_normalize(image, min_=0.0, max_=1.0, output_dtype=np.int16):
553 output = np.empty(shape=image.shape, dtype=output_dtype) 564 output = np.empty(shape=image.shape, dtype=output_dtype)
554 imin, imax = image.min(), image.max() 565 imin, imax = image.min(), image.max()
@@ -595,7 +606,7 @@ def convert_invesalius_to_voxel(position): @@ -595,7 +606,7 @@ def convert_invesalius_to_voxel(position):
595 :return: a vector of 3 coordinates in the voxel space 606 :return: a vector of 3 coordinates in the voxel space
596 """ 607 """
597 slice = sl.Slice() 608 slice = sl.Slice()
598 - return np.array((position[0], slice.matrix.shape[1] - position[1] - 1, position[2])) 609 + return np.array((position[0], slice.spacing[1]*(slice.matrix.shape[1] - 1) - position[1], position[2]))
599 610
600 611
601 def convert_invesalius_to_world(position, orientation): 612 def convert_invesalius_to_world(position, orientation):
invesalius/data/styles.py
@@ -45,6 +45,7 @@ import invesalius.utils as utils @@ -45,6 +45,7 @@ import invesalius.utils as utils
45 from invesalius.data.measures import (CircleDensityMeasure, MeasureData, 45 from invesalius.data.measures import (CircleDensityMeasure, MeasureData,
46 PolygonDensityMeasure) 46 PolygonDensityMeasure)
47 47
  48 +from invesalius.data.imagedata_utils import get_LUT_value, get_LUT_value_255
48 from invesalius_cy import floodfill 49 from invesalius_cy import floodfill
49 50
50 # For tracts 51 # For tracts
@@ -69,26 +70,6 @@ WATERSHED_OPERATIONS = {_(&quot;Erase&quot;): BRUSH_ERASE, @@ -69,26 +70,6 @@ WATERSHED_OPERATIONS = {_(&quot;Erase&quot;): BRUSH_ERASE,
69 _("Foreground"): BRUSH_FOREGROUND, 70 _("Foreground"): BRUSH_FOREGROUND,
70 _("Background"): BRUSH_BACKGROUND,} 71 _("Background"): BRUSH_BACKGROUND,}
71 72
72 -def get_LUT_value(data, window, level):  
73 - shape = data.shape  
74 - data_ = data.ravel()  
75 - data = np.piecewise(data_,  
76 - [data_ <= (level - 0.5 - (window-1)/2),  
77 - data_ > (level - 0.5 + (window-1)/2)],  
78 - [0, window, lambda data_: ((data_ - (level - 0.5))/(window-1) + 0.5)*(window)])  
79 - data.shape = shape  
80 - return data  
81 -  
82 -def get_LUT_value_255(data, window, level):  
83 - shape = data.shape  
84 - data_ = data.ravel()  
85 - data = np.piecewise(data_,  
86 - [data_ <= (level - 0.5 - (window-1)/2),  
87 - data_ > (level - 0.5 + (window-1)/2)],  
88 - [0, 255, lambda data_: ((data_ - (level - 0.5))/(window-1) + 0.5)*(255)])  
89 - data.shape = shape  
90 - return data  
91 -  
92 73
93 class BaseImageInteractorStyle(vtk.vtkInteractorStyleImage): 74 class BaseImageInteractorStyle(vtk.vtkInteractorStyleImage):
94 def __init__(self, viewer): 75 def __init__(self, viewer):
invesalius/data/surface.py
@@ -51,6 +51,7 @@ else: @@ -51,6 +51,7 @@ else:
51 51
52 import invesalius.constants as const 52 import invesalius.constants as const
53 import invesalius.data.imagedata_utils as iu 53 import invesalius.data.imagedata_utils as iu
  54 +import invesalius.data.slice_ as sl
54 import invesalius.data.polydata_utils as pu 55 import invesalius.data.polydata_utils as pu
55 import invesalius.project as prj 56 import invesalius.project as prj
56 import invesalius.session as ses 57 import invesalius.session as ses
@@ -159,7 +160,6 @@ class SurfaceManager(): @@ -159,7 +160,6 @@ class SurfaceManager():
159 def __init__(self): 160 def __init__(self):
160 self.actors_dict = {} 161 self.actors_dict = {}
161 self.last_surface_index = 0 162 self.last_surface_index = 0
162 - self.affine_vtk = None  
163 self.convert2inv = None 163 self.convert2inv = None
164 self.__bind_events() 164 self.__bind_events()
165 165
@@ -207,7 +207,6 @@ class SurfaceManager(): @@ -207,7 +207,6 @@ class SurfaceManager():
207 207
208 Publisher.subscribe(self.OnImportSurfaceFile, 'Import surface file') 208 Publisher.subscribe(self.OnImportSurfaceFile, 'Import surface file')
209 209
210 - Publisher.subscribe(self.UpdateAffineMatrix, 'Update affine matrix')  
211 Publisher.subscribe(self.UpdateConvert2InvFlag, 'Update convert2inv flag') 210 Publisher.subscribe(self.UpdateConvert2InvFlag, 'Update convert2inv flag')
212 211
213 Publisher.subscribe(self.CreateSurfaceFromPolydata, 'Create surface from polydata') 212 Publisher.subscribe(self.CreateSurfaceFromPolydata, 'Create surface from polydata')
@@ -338,16 +337,6 @@ class SurfaceManager(): @@ -338,16 +337,6 @@ class SurfaceManager():
338 name = os.path.splitext(os.path.split(filename)[-1])[0] 337 name = os.path.splitext(os.path.split(filename)[-1])[0]
339 self.CreateSurfaceFromPolydata(polydata, name=name, scalar=scalar) 338 self.CreateSurfaceFromPolydata(polydata, name=name, scalar=scalar)
340 339
341 - def UpdateAffineMatrix(self, affine):  
342 - if affine is not None:  
343 - prj_data = prj.Project()  
344 - matrix_shape = tuple(prj_data.matrix_shape)  
345 - affine = affine.copy()  
346 - affine[1, -1] -= matrix_shape[1]  
347 - self.affine_vtk = vtk_utils.numpy_to_vtkMatrix4x4(affine)  
348 - else:  
349 - self.affine_vtk = None  
350 -  
351 def UpdateConvert2InvFlag(self, convert2inv=False): 340 def UpdateConvert2InvFlag(self, convert2inv=False):
352 self.convert2inv = convert2inv 341 self.convert2inv = convert2inv
353 342
@@ -373,12 +362,17 @@ class SurfaceManager(): @@ -373,12 +362,17 @@ class SurfaceManager():
373 actor.SetMapper(mapper) 362 actor.SetMapper(mapper)
374 actor.GetProperty().SetBackfaceCulling(1) 363 actor.GetProperty().SetBackfaceCulling(1)
375 364
376 - if self.convert2inv and (self.affine_vtk is not None):  
377 - actor.SetUserMatrix(self.affine_vtk) 365 + if self.convert2inv:
  366 + # convert between invesalius and world space with shift in the Y coordinate
  367 + affine = sl.Slice().affine
  368 + if affine is not None:
  369 + affine[1, -1] -= sl.Slice().spacing[1] * (sl.Slice().matrix.shape[1] - 1)
  370 + affine_vtk = vtk_utils.numpy_to_vtkMatrix4x4(affine)
  371 + actor.SetUserMatrix(affine_vtk)
378 372
379 if overwrite: 373 if overwrite:
380 if index is None: 374 if index is None:
381 - index = self.last_surface_index 375 + index = self.last_surface_index
382 surface = Surface(index=index) 376 surface = Surface(index=index)
383 else: 377 else:
384 surface = Surface() 378 surface = Surface()
invesalius/data/viewer_volume.py
@@ -1455,7 +1455,8 @@ class Viewer(wx.Panel): @@ -1455,7 +1455,8 @@ class Viewer(wx.Panel):
1455 self.ren.RemoveActor(self.object_orientation_torus_actor) 1455 self.ren.RemoveActor(self.object_orientation_torus_actor)
1456 self.ren.RemoveActor(self.obj_projection_arrow_actor) 1456 self.ren.RemoveActor(self.obj_projection_arrow_actor)
1457 self.actor_peel = None 1457 self.actor_peel = None
1458 - self.ball_actor.SetVisibility(1) 1458 + if self.ball_actor:
  1459 + self.ball_actor.SetVisibility(1)
1459 1460
1460 if flag and actor: 1461 if flag and actor:
1461 self.ren.AddActor(actor) 1462 self.ren.AddActor(actor)
invesalius/gui/dialogs.py
@@ -4208,37 +4208,23 @@ class GoToDialogScannerCoord(wx.Dialog): @@ -4208,37 +4208,23 @@ class GoToDialogScannerCoord(wx.Dialog):
4208 self.__bind_events() 4208 self.__bind_events()
4209 4209
4210 btn_ok.Bind(wx.EVT_BUTTON, self.OnOk) 4210 btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
4211 - Publisher.sendMessage('Get affine matrix')  
4212 4211
4213 def __bind_events(self): 4212 def __bind_events(self):
4214 Publisher.subscribe(self.SetNewFocalPoint, 'Cross focal point') 4213 Publisher.subscribe(self.SetNewFocalPoint, 'Cross focal point')
4215 - Publisher.subscribe(self.UpdateAffineMatrix, 'Update affine matrix')  
4216 -  
4217 - def UpdateAffineMatrix(self, affine):  
4218 - self.affine = affine  
4219 4214
4220 def SetNewFocalPoint(self, coord, spacing): 4215 def SetNewFocalPoint(self, coord, spacing):
4221 Publisher.sendMessage('Update cross pos', coord=self.result*spacing) 4216 Publisher.sendMessage('Update cross pos', coord=self.result*spacing)
4222 4217
4223 def OnOk(self, evt): 4218 def OnOk(self, evt):
4224 - from numpy.linalg import inv  
4225 import invesalius.data.slice_ as slc 4219 import invesalius.data.slice_ as slc
4226 try: 4220 try:
4227 - #get affine from image import  
4228 - if self.affine is not None:  
4229 - affine = self.affine  
4230 - #get affine from project  
4231 - else:  
4232 - from invesalius.project import Project  
4233 - affine = Project().affine  
4234 -  
4235 point = [float(self.goto_sagital.GetValue()), 4221 point = [float(self.goto_sagital.GetValue()),
4236 float(self.goto_coronal.GetValue()), 4222 float(self.goto_coronal.GetValue()),
4237 float(self.goto_axial.GetValue())] 4223 float(self.goto_axial.GetValue())]
4238 4224
4239 # transformation from scanner coordinates to inv coord system 4225 # transformation from scanner coordinates to inv coord system
4240 - affine = inv(affine)  
4241 - self.result = np.dot(affine[:3, :3], np.transpose(point[0:3])) + affine[:3, 3] 4226 + affine_inverse = np.linalg.inv(slc.Slice().affine)
  4227 + self.result = np.dot(affine_inverse[:3, :3], np.transpose(point[0:3])) + affine_inverse[:3, 3]
4242 self.result[1] = slc.Slice().GetMaxSliceNumber(const.CORONAL_STR) - self.result[1] 4228 self.result[1] = slc.Slice().GetMaxSliceNumber(const.CORONAL_STR) - self.result[1]
4243 4229
4244 Publisher.sendMessage('Update status text in GUI', label=_("Calculating the transformation ...")) 4230 Publisher.sendMessage('Update status text in GUI', label=_("Calculating the transformation ..."))
invesalius/gui/frame.py
@@ -892,7 +892,7 @@ class MenuBar(wx.MenuBar): @@ -892,7 +892,7 @@ class MenuBar(wx.MenuBar):
892 sub(self.OnEnableState, "Enable state project") 892 sub(self.OnEnableState, "Enable state project")
893 sub(self.OnEnableUndo, "Enable undo") 893 sub(self.OnEnableUndo, "Enable undo")
894 sub(self.OnEnableRedo, "Enable redo") 894 sub(self.OnEnableRedo, "Enable redo")
895 - sub(self.OnEnableGotoCoord, "Update affine matrix") 895 + sub(self.OnEnableGotoCoord, "Enable Go-to-Coord")
896 sub(self.OnEnableNavigation, "Navigation status") 896 sub(self.OnEnableNavigation, "Navigation status")
897 897
898 sub(self.OnAddMask, "Add mask") 898 sub(self.OnAddMask, "Add mask")
@@ -1242,15 +1242,13 @@ class MenuBar(wx.MenuBar): @@ -1242,15 +1242,13 @@ class MenuBar(wx.MenuBar):
1242 else: 1242 else:
1243 self.FindItemById(wx.ID_REDO).Enable(False) 1243 self.FindItemById(wx.ID_REDO).Enable(False)
1244 1244
1245 - def OnEnableGotoCoord(self, affine): 1245 + def OnEnableGotoCoord(self, status=True):
1246 """ 1246 """
1247 - Disable goto coord either if there is no affine matrix or affine is wrongly imported.  
1248 - :param status: Affine matrix status 1247 + Enable or disable goto coord depending on the imported affine matrix.
  1248 + :param status: True for enabling and False for disabling the Go-To-Coord
1249 """ 1249 """
1250 - if affine is not None:  
1251 - self.FindItemById(const.ID_GOTO_COORD).Enable(True)  
1252 - else:  
1253 - self.FindItemById(const.ID_GOTO_COORD).Enable(False) 1250 +
  1251 + self.FindItemById(const.ID_GOTO_COORD).Enable(status)
1254 1252
1255 def OnEnableNavigation(self, nav_status, vis_status): 1253 def OnEnableNavigation(self, nav_status, vis_status):
1256 """ 1254 """
invesalius/gui/task_navigator.py
@@ -691,8 +691,8 @@ class NeuronavigationPanel(wx.Panel): @@ -691,8 +691,8 @@ class NeuronavigationPanel(wx.Panel):
691 size = 2 691 size = 2
692 seed = 3 * [0.] 692 seed = 3 * [0.]
693 693
694 - Publisher.sendMessage('Create marker', coord=coord, colour=colour, size=size, label=label, seed=seed)  
695 - 694 + Publisher.sendMessage('Create marker', coord=coord, colour=colour, size=size,
  695 + label=label, seed=seed)
696 else: 696 else:
697 for m in [0, 1, 2]: 697 for m in [0, 1, 2]:
698 self.numctrls_fiducial[n][m].SetValue(float(self.current_coord[m])) 698 self.numctrls_fiducial[n][m].SetValue(float(self.current_coord[m]))
@@ -1189,11 +1189,11 @@ class MarkersPanel(wx.Panel): @@ -1189,11 +1189,11 @@ class MarkersPanel(wx.Panel):
1189 res += '\t'.join(map(lambda x: 'N/A' if x is None else str(x), (*position_world, *orientation_world))) 1189 res += '\t'.join(map(lambda x: 'N/A' if x is None else str(x), (*position_world, *orientation_world)))
1190 return res 1190 return res
1191 1191
1192 - def from_string(self, str):  
1193 - """Deserialize from a tab-separated string. If the string is not 1192 + def from_string(self, inp_str):
  1193 + """Deserialize from a tab-separated string. If the string is not
1194 properly formatted, might throw an exception and leave the object 1194 properly formatted, might throw an exception and leave the object
1195 in an inconsistent state.""" 1195 in an inconsistent state."""
1196 - for field, str_val in zip(dataclasses.fields(self.__class__), str.split('\t')): 1196 + for field, str_val in zip(dataclasses.fields(self.__class__), inp_str.split('\t')):
1197 if field.type is float: 1197 if field.type is float:
1198 setattr(self, field.name, float(str_val)) 1198 setattr(self, field.name, float(str_val))
1199 if field.type is int: 1199 if field.type is int:
@@ -1294,7 +1294,7 @@ class MarkersPanel(wx.Panel): @@ -1294,7 +1294,7 @@ class MarkersPanel(wx.Panel):
1294 self.lc.InsertColumn(1, 'X') 1294 self.lc.InsertColumn(1, 'X')
1295 self.lc.InsertColumn(2, 'Y') 1295 self.lc.InsertColumn(2, 'Y')
1296 self.lc.InsertColumn(3, 'Z') 1296 self.lc.InsertColumn(3, 'Z')
1297 - self.lc.InsertColumn(4, 'ID') 1297 + self.lc.InsertColumn(4, 'Label')
1298 self.lc.InsertColumn(5, 'Target') 1298 self.lc.InsertColumn(5, 'Target')
1299 self.lc.InsertColumn(6, 'Session') 1299 self.lc.InsertColumn(6, 'Session')
1300 1300
@@ -2125,7 +2125,7 @@ class SessionPanel(wx.Panel): @@ -2125,7 +2125,7 @@ class SessionPanel(wx.Panel):
2125 except AttributeError: 2125 except AttributeError:
2126 default_colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_MENUBAR) 2126 default_colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_MENUBAR)
2127 self.SetBackgroundColour(default_colour) 2127 self.SetBackgroundColour(default_colour)
2128 - 2128 +
2129 # session count spinner 2129 # session count spinner
2130 self.__spin_session = wx.SpinCtrl(self, -1, "", size=wx.Size(40, 23)) 2130 self.__spin_session = wx.SpinCtrl(self, -1, "", size=wx.Size(40, 23))
2131 self.__spin_session.SetRange(1, 99) 2131 self.__spin_session.SetRange(1, 99)
@@ -2133,13 +2133,13 @@ class SessionPanel(wx.Panel): @@ -2133,13 +2133,13 @@ class SessionPanel(wx.Panel):
2133 2133
2134 self.__spin_session.Bind(wx.EVT_TEXT, self.OnSessionChanged) 2134 self.__spin_session.Bind(wx.EVT_TEXT, self.OnSessionChanged)
2135 self.__spin_session.Bind(wx.EVT_SPINCTRL, self.OnSessionChanged) 2135 self.__spin_session.Bind(wx.EVT_SPINCTRL, self.OnSessionChanged)
2136 - 2136 +
2137 sizer_create = wx.FlexGridSizer(rows=1, cols=1, hgap=5, vgap=5) 2137 sizer_create = wx.FlexGridSizer(rows=1, cols=1, hgap=5, vgap=5)
2138 sizer_create.AddMany([(self.__spin_session, 1)]) 2138 sizer_create.AddMany([(self.__spin_session, 1)])
2139 2139
2140 def OnSessionChanged(self, evt): 2140 def OnSessionChanged(self, evt):
2141 Publisher.sendMessage('Current session changed', new_session_id=self.__spin_session.GetValue()) 2141 Publisher.sendMessage('Current session changed', new_session_id=self.__spin_session.GetValue())
2142 - 2142 +
2143 2143
2144 class InputAttributes(object): 2144 class InputAttributes(object):
2145 # taken from https://stackoverflow.com/questions/2466191/set-attributes-from-dictionary-in-python 2145 # taken from https://stackoverflow.com/questions/2466191/set-attributes-from-dictionary-in-python
invesalius/project.py
@@ -329,8 +329,6 @@ class Project(metaclass=Singleton): @@ -329,8 +329,6 @@ class Project(metaclass=Singleton):
329 329
330 if project.get("affine", ""): 330 if project.get("affine", ""):
331 self.affine = project["affine"] 331 self.affine = project["affine"]
332 - Publisher.sendMessage('Update affine matrix',  
333 - affine=np.asarray(self.affine).reshape(4, 4))  
334 332
335 # Opening the masks 333 # Opening the masks
336 self.mask_dict = TwoWaysDictionary() 334 self.mask_dict = TwoWaysDictionary()
invesalius/segmentation/brain/segment.py
@@ -22,17 +22,6 @@ SIZE = 48 @@ -22,17 +22,6 @@ SIZE = 48
22 OVERLAP = SIZE // 2 + 1 22 OVERLAP = SIZE // 2 + 1
23 23
24 24
25 -def get_LUT_value(data, window, level):  
26 - shape = data.shape  
27 - data_ = data.ravel()  
28 - data = np.piecewise(data_,  
29 - [data_ <= (level - 0.5 - (window-1)/2),  
30 - data_ > (level - 0.5 + (window-1)/2)],  
31 - [0, window, lambda data_: ((data_ - (level - 0.5))/(window-1) + 0.5)*(window)])  
32 - data.shape = shape  
33 - return data  
34 -  
35 -  
36 def gen_patches(image, patch_size, overlap): 25 def gen_patches(image, patch_size, overlap):
37 sz, sy, sx = image.shape 26 sz, sy, sx = image.shape
38 i_cuts = list( 27 i_cuts = list(
@@ -188,8 +177,7 @@ class SegmentProcess(ctx.Process): @@ -188,8 +177,7 @@ class SegmentProcess(ctx.Process):
188 ) 177 )
189 178
190 if self.apply_wwwl: 179 if self.apply_wwwl:
191 - print("Applying window level")  
192 - image = get_LUT_value(image, self.window_width, self.window_level) 180 + image = imagedata_utils.get_LUT_value(image, self.window_width, self.window_level)
193 181
194 probability_array = np.memmap( 182 probability_array = np.memmap(
195 self._prob_array_filename, 183 self._prob_array_filename,