def ImportMedicalImages(self, directory, gui=True): patients_groups = dcm.GetDicomGroups(directory) name = directory.rpartition('\\')[-1].split('.') print("patients: ", patients_groups) if len(patients_groups): # OPTION 1: DICOM group = dcm.SelectLargerDicomGroup(patients_groups) matrix, matrix_filename, dicom = self.OpenDicomGroup(group, 0, [0, 0], gui=gui) self.CreateDicomProject(dicom, matrix, matrix_filename) else: # OPTION 2: NIfTI, Analyze or PAR/REC if name[-1] == 'gz': name[1] = 'nii.gz' suptype = ('hdr', 'nii', 'nii.gz', 'par') filetype = name[1].lower() if filetype in suptype: group = oth.ReadOthers(directory) else: utils.debug("No medical images found on given directory") return matrix, matrix_filename = self.OpenOtherFiles(group) self.CreateOtherProject(str(name[0]), matrix, matrix_filename) # OPTION 4: Nothing... self.LoadProject() Publisher.sendMessage("Enable state project", state=True)
def _export_surface(self, filename, filetype): if filetype in (const.FILETYPE_STL, const.FILETYPE_VTP, const.FILETYPE_PLY, const.FILETYPE_STL_ASCII): # First we identify all surfaces that are selected # (if any) proj = prj.Project() polydata_list = [] for index in proj.surface_dict: surface = proj.surface_dict[index] if surface.is_shown: polydata_list.append(surface.polydata) if len(polydata_list) == 0: utl.debug("oops - no polydata") return elif len(polydata_list) == 1: polydata = polydata_list[0] else: polydata = pu.Merge(polydata_list) # Having a polydata that represents all surfaces # selected, we write it, according to filetype if filetype == const.FILETYPE_STL: writer = vtk.vtkSTLWriter() writer.SetFileTypeToBinary() elif filetype == const.FILETYPE_STL_ASCII: writer = vtk.vtkSTLWriter() writer.SetFileTypeToASCII() elif filetype == const.FILETYPE_VTP: writer = vtk.vtkXMLPolyDataWriter() #elif filetype == const.FILETYPE_IV: # writer = vtk.vtkIVWriter() elif filetype == const.FILETYPE_PLY: writer = vtk.vtkPLYWriter() writer.SetFileTypeToASCII() writer.SetColorModeToOff() #writer.SetDataByteOrderToLittleEndian() #writer.SetColorModeToUniformCellColor() #writer.SetColor(255, 0, 0) if filetype in (const.FILETYPE_STL, const.FILETYPE_STL_ASCII, const.FILETYPE_PLY): # Invert normals normals = vtk.vtkPolyDataNormals() normals.SetInputData(polydata) normals.SetFeatureAngle(80) normals.AutoOrientNormalsOn() # normals.GetOutput().ReleaseDataFlagOn() normals.UpdateInformation() normals.Update() polydata = normals.GetOutput() filename = filename.encode(const.FS_ENCODE) writer.SetFileName(filename) writer.SetInputData(polydata) writer.Write()
def _display_previews(self): initial = self.displayed_position * NCOLS final = initial + NUM_PREVIEWS if len(self.files) < final: for i in range(final-len(self.files)): try: self.previews[-i-1].Hide() except IndexError: utils.debug("doesn't exist!") self.nhidden_last_display = final-len(self.files) else: if self.nhidden_last_display: for i in range(self.nhidden_last_display): try: self.previews[-i-1].Show() except IndexError: utils.debug("doesn't exist!") self.nhidden_last_display = 0 for f, p in zip(self.files[initial:final], self.previews): p.SetDicomToPreview(f) if f.selected: self.selected_panel = p #p.interactor.Render() for f, p in zip(self.files[initial:final], self.previews): p.Show()
def CloseProject(self): import invesalius.constants as const debug("Session.CloseProject") self.project_path = () self.project_status = const.PROJ_CLOSE #self.mode = const.MODE_RP self.temp_item = False self.WriteSessionFile()
def RemoveActor(self, pubsub_evt): utils.debug("RemoveActor") actor = pubsub_evt.data ren = self.ren ren.RemoveActor(actor) self.interactor.Render() self._to_show_ball -= 1 self._check_and_set_ball_visibility()
def SaveProject(self, path=()): import invesalius.constants as const debug("Session.SaveProject") self.project_status = const.PROJ_OPEN if path: self.project_path = path self.__add_to_list(path) if self.temp_item: self.temp_item = False self.WriteSessionFile()
def CreateProject(self, filename): import invesalius.constants as const debug("Session.CreateProject") Publisher.sendMessage('Begin busy cursor') # Set session info self.project_path = (self.tempdir, filename) self.project_status = const.PROJ_NEW self.temp_item = True self.WriteSessionFile() return self.tempdir
def SetAcquisitionModality(self, type_=None): if type_ is None: type_ = self.modality if type_ == "MRI": self.threshold_modes = self.presets.thresh_mri elif type_ == "CT": self.threshold_modes = self.presets.thresh_ct else: debug("Different Acquisition Modality!!!") self.modality = type_
def OpenProject(self, filepath): import invesalius.constants as const debug("Session.OpenProject") # Add item to recent projects list item = (path, file) = os.path.split(filepath) self.__add_to_list(item) # Set session info self.project_path = item self.project_status = const.PROJ_OPEN self.WriteSessionFile()
def OnRun(self): pos = self.slider.GetValue() pos += 1 if not (self.nimages- pos): pos = 0 self.slider.SetValue(pos) self.ShowSlice(pos) time.sleep(0.2) if self.ischecked: try: wx.Yield() #TODO: temporary fix necessary in the Windows XP 64 Bits #BUG in wxWidgets http://trac.wxwidgets.org/ticket/10896 except(wx._core.PyAssertionError): utils.debug("wx._core.PyAssertionError") finally: wx.CallAfter(self.OnRun)
def ImportMedicalImages(self, directory): # OPTION 1: DICOM? patients_groups = dcm.GetDicomGroups(directory) if len(patients_groups): group = dcm.SelectLargerDicomGroup(patients_groups) matrix, matrix_filename, dicom = self.OpenDicomGroup(group, 0, [0,0],gui=True) self.CreateDicomProject(dicom, matrix, matrix_filename) # OPTION 2: ANALYZE? else: imagedata = analyze.ReadDirectory(directory) if imagedata: self.CreateAnalyzeProject(imagedata) # OPTION 3: Nothing... else: utils.debug("No medical images found on given directory") return self.LoadProject() Publisher.sendMessage("Enable state project", True)
def ShowDialogCloseProject(self): session = ses.Session() st = session.project_status print('Status', st, type(st)) if st == const.PROJ_CLOSE: return -1 try: filename = session.project_path[1] except(AttributeError): utils.debug("Project doesn't exist") filename = None if (filename): if (st == const.PROJ_NEW) or (st == const.PROJ_CHANGE): answer = dialog.SaveChangesDialog(filename, self.frame) if not answer: utils.debug("Close without changes") self.CloseProject() Publisher.sendMessage("Enable state project", state=False) Publisher.sendMessage('Set project name') Publisher.sendMessage("Stop Config Recording") elif answer == 1: self.ShowDialogSaveProject() utils.debug("Save changes and close") self.CloseProject() Publisher.sendMessage("Enable state project", state=False) Publisher.sendMessage('Set project name') Publisher.sendMessage("Stop Config Recording") elif answer == -1: utils.debug("Cancel") else: self.CloseProject() Publisher.sendMessage("Enable state project", state=False) Publisher.sendMessage('Set project name') Publisher.sendMessage("Stop Config Recording") else: Publisher.sendMessage('Stop Config Recording')
def Update(self): # Ideally, AddFile would be sufficient for splitting DICOM # files into groups (series). However, this does not work for # acquisitions / equipments and manufacturers. # Although DICOM is a protocol, each one uses its fields in a # different manner # Check if Problem 1 occurs (n groups with 1 slice each) is_there_problem_1 = False utils.debug("n slice %d" % self.nslices) utils.debug("len %d" % len(self.groups_dict)) if (self.nslices == len(self.groups_dict)) and\ (self.nslices > 1): is_there_problem_1 = True # Fix Problem 1 if is_there_problem_1: utils.debug("Problem1") self.groups_dict = self.FixProblem1(self.groups_dict)
def print_events(data): """ Print pubsub messages """ utils.debug(data.topic)
def ChangeProject(self): import invesalius.constants as const debug("Session.ChangeProject") self.project_status = const.PROJ_CHANGE
def print_events(topic=Publisher.AUTO_TOPIC, **msg_data): """ Print pubsub messages """ utils.debug("%s\n\tParameters: %s" % (topic, msg_data))
def SetDicomDirectory(self, directory): utils.debug("Setting Dicom Directory %s" % directory) self.directory = directory self.series = dicom_reader.GetSeries(directory)[0]
def RemoveAllActor(self, pubsub_evt): utils.debug("RemoveAllActor") self.ren.RemoveAllProps() Publisher.sendMessage('Render volume viewer')
def OpenDicomGroup(self, dicom_group, interval, file_range, gui=True): # Retrieve general DICOM headers dicom = dicom_group.GetDicomSample() # Create imagedata interval += 1 filelist = dicom_group.GetFilenameList()[::interval] if not filelist: utils.debug("Not used the IPPSorter") filelist = [i.image.file for i in dicom_group.GetHandSortedList()[::interval]] if file_range is not None and file_range[0] is not None and file_range[1] > file_range[0]: filelist = filelist[file_range[0]:file_range[1] + 1] zspacing = dicom_group.zspacing * interval size = dicom.image.size bits = dicom.image.bits_allocad sop_class_uid = dicom.acquisition.sop_class_uid xyspacing = dicom.image.spacing orientation = dicom.image.orientation_label wl = float(dicom.image.level) ww = float(dicom.image.window) if sop_class_uid == '1.2.840.10008.5.1.4.1.1.7': #Secondary Capture Image Storage use_dcmspacing = 1 else: use_dcmspacing = 0 imagedata = None if dicom.image.number_of_frames == 1: sx, sy = size n_slices = len(filelist) resolution_percentage = utils.calculate_resizing_tofitmemory(int(sx), int(sy), n_slices, bits/8) if resolution_percentage < 1.0 and gui: re_dialog = dialog.ResizeImageDialog() re_dialog.SetValue(int(resolution_percentage*100)) re_dialog_value = re_dialog.ShowModal() re_dialog.Close() if re_dialog_value == wx.ID_OK: percentage = re_dialog.GetValue() resolution_percentage = percentage / 100.0 else: return xyspacing = xyspacing[0] / resolution_percentage, xyspacing[1] / resolution_percentage self.matrix, scalar_range, self.filename = image_utils.dcm2memmap(filelist, size, orientation, resolution_percentage) print(xyspacing, zspacing) if orientation == 'AXIAL': spacing = xyspacing[0], xyspacing[1], zspacing elif orientation == 'CORONAL': spacing = xyspacing[0], zspacing, xyspacing[1] elif orientation == 'SAGITTAL': spacing = zspacing, xyspacing[1], xyspacing[0] else: self.matrix, spacing, scalar_range, self.filename = image_utils.dcmmf2memmap(filelist[0], orientation) self.Slice = sl.Slice() self.Slice.matrix = self.matrix self.Slice.matrix_filename = self.filename self.Slice.spacing = spacing # 1(a): Fix gantry tilt, if any tilt_value = dicom.acquisition.tilt if (tilt_value) and (gui): # Tell user gantry tilt and fix, according to answer message = _("Fix gantry tilt applying the degrees below") value = -1*tilt_value tilt_value = dialog.ShowNumberDialog(message, value) image_utils.FixGantryTilt(self.matrix, self.Slice.spacing, tilt_value) elif (tilt_value) and not (gui): tilt_value = -1*tilt_value image_utils.FixGantryTilt(self.matrix, self.Slice.spacing, tilt_value) self.Slice.window_level = wl self.Slice.window_width = ww scalar_range = int(self.matrix.min()), int(self.matrix.max()) Publisher.sendMessage('Update threshold limits list', threshold_range=scalar_range) return self.matrix, self.filename, dicom
def CancelImageDataLoad(self, evt_pusub): utils.debug("Canceling") self.running = False
def CreateImageData(self, filelist, zspacing, size, bits): message = _("Generating multiplanar visualization...") if not const.VTK_WARNING: log_path = os.path.join(const.USER_LOG_DIR, 'vtkoutput.txt') fow = vtk.vtkFileOutputWindow() fow.SetFileName(log_path) ow = vtk.vtkOutputWindow() ow.SetInstance(fow) x,y = size px, py = utils.predict_memory(len(filelist), x, y, bits) utils.debug("Image Resized to >>> %f x %f" % (px, py)) if (x == px) and (y == py): const.REDUCE_IMAGEDATA_QUALITY = 0 else: const.REDUCE_IMAGEDATA_QUALITY = 1 if not(const.REDUCE_IMAGEDATA_QUALITY): update_progress= vtk_utils.ShowProgress(1, dialog_type = "ProgressDialog") array = vtk.vtkStringArray() for x in range(len(filelist)): if not self.running: return False array.InsertValue(x,filelist[x]) if not self.running: return False reader = vtkgdcm.vtkGDCMImageReader() reader.SetFileNames(array) reader.AddObserver("ProgressEvent", lambda obj,evt: update_progress(reader,message)) reader.Update() if not self.running: reader.AbortExecuteOn() return False # The zpacing is a DicomGroup property, so we need to set it imagedata = vtk.vtkImageData() imagedata.DeepCopy(reader.GetOutput()) spacing = imagedata.GetSpacing() imagedata.SetSpacing(spacing[0], spacing[1], zspacing) else: update_progress= vtk_utils.ShowProgress(2*len(filelist), dialog_type = "ProgressDialog") # Reformat each slice and future append them appender = vtk.vtkImageAppend() appender.SetAppendAxis(2) #Define Stack in Z # Reformat each slice for x in range(len(filelist)): # TODO: We need to check this automatically according # to each computer's architecture # If the resolution of the matrix is too large if not self.running: return False reader = vtkgdcm.vtkGDCMImageReader() reader.SetFileName(filelist[x]) reader.AddObserver("ProgressEvent", lambda obj,evt: update_progress(reader,message)) reader.Update() #Resample image in x,y dimension slice_imagedata = ResampleImage2D(reader.GetOutput(), px, py, update_progress) #Stack images in Z axes appender.AddInput(slice_imagedata) #appender.AddObserver("ProgressEvent", lambda obj,evt:update_progress(appender)) appender.Update() # The zpacing is a DicomGroup property, so we need to set it if not self.running: return False imagedata = vtk.vtkImageData() imagedata.DeepCopy(appender.GetOutput()) spacing = imagedata.GetSpacing() imagedata.SetSpacing(spacing[0], spacing[1], zspacing) imagedata.AddObserver("ProgressEvent", lambda obj,evt: update_progress(imagedata,message)) imagedata.Update() return imagedata