From 3274c0c448ad64f28f68392934fbc92b7d4ae6e1 Mon Sep 17 00:00:00 2001 From: "Stephen R. Aylward" Date: Wed, 3 Jul 2024 09:05:02 -0400 Subject: [PATCH] ENH: Major update to handle image/mask orientation and more (#37) --- .gitignore | 5 + README_Dev.md | 7 + data/.gitignore | 4 + pyproject.toml | 1 + src/minder3d/lib/sovImageTablePanelWidget.py | 12 + src/minder3d/lib/sovInfoTablePanelWidget.py | 74 +++++- src/minder3d/lib/sovObjectPanelWidget.py | 11 +- src/minder3d/lib/sovOtsuLogic.py | 3 +- src/minder3d/lib/sovUtils.py | 52 ++++ src/minder3d/lib/sovView2DPanelWidget.py | 16 +- src/minder3d/lib/sovView2DPanelWidget.ui | 8 +- .../lib/sovView2DRenderWindowInteractor.py | 3 - src/minder3d/lib/sovView3DPanelWidget.ui | 225 +++++++++++------- .../lib/sovView3DRenderWindowInteractor.py | 2 + src/minder3d/lib/sovView3DUtils.py | 2 +- .../lib/sovVisualizationPanelWidget.ui | 56 ++++- src/minder3d/lib/sovWelcomePanelWidget.py | 6 - src/minder3d/lib/sovWelcomePanelWidget.ui | 62 ++--- src/minder3d/lib/ui_sovView2DPanelWidget.py | 5 +- src/minder3d/lib/ui_sovView3DPanelWidget.py | 134 ++++++----- .../lib/ui_sovVisualizationPanelWidget.py | 30 ++- src/minder3d/lib/ui_sovWelcomePanelWidget.py | 44 +--- src/minder3d/minder3DWindow.py | 22 +- src/minder3d/minder3DWindow.ui | 10 +- src/minder3d/ui_minder3DWindow.py | 12 +- 25 files changed, 531 insertions(+), 275 deletions(-) diff --git a/.gitignore b/.gitignore index ddde42e..d5244cf 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,8 @@ __pycache__ *.swp *~ *.zip +itk-wheels +*.tre +*.mha +*.nii +*.code-workspace diff --git a/README_Dev.md b/README_Dev.md index e270844..4d475bb 100644 --- a/README_Dev.md +++ b/README_Dev.md @@ -1,12 +1,19 @@ +Install the developer build of ITK, ITKMinimalPathExtraction ITKTubetk: + + python -m pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ itk itk-minimalpathextraction itk-tubetk + Setup for editable installation. Changes to code in src are immediatelly reflected in the installed version. Also installs all dependencies needed for development and testing: + pip install -e .[dev] Prior to making a commit, please verify your code is compliant: + pre-commit run --all-files HINT: QT Designer was used to define the layout. On Windows, to launch designer, use this command: + qt6-tools.exe designer pytubeview.ui diff --git a/data/.gitignore b/data/.gitignore index 33266fd..2054306 100644 --- a/data/.gitignore +++ b/data/.gitignore @@ -6,3 +6,7 @@ *.nii.gz *.mhd *.raw +test* +CH* +PCD* +UNC* diff --git a/pyproject.toml b/pyproject.toml index b2ce745..6b67377 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ dependencies = [ 'vtk', 'thedicomsort', #'itk', # Do not install until ITK pypi is updated + #'itk-tubetk', # Do not install until ITK pypi is updated ] [project.scripts] diff --git a/src/minder3d/lib/sovImageTablePanelWidget.py b/src/minder3d/lib/sovImageTablePanelWidget.py index a5fe323..36fc24d 100644 --- a/src/minder3d/lib/sovImageTablePanelWidget.py +++ b/src/minder3d/lib/sovImageTablePanelWidget.py @@ -88,10 +88,22 @@ def remove_all(self): self.settings.clear_data() self.fill_table() + def close_expanded_table(self): + self.enlarged_table.close() + self.enlarged_table = None + def expand_table(self): if self.enlarged_table is None: self.enlarged_table = ImageTablePanelWidget(self.gui, self.state) self.enlarged_table.setWindowTitle('Image Table') + self.enlarged_table.imageTableExpandButton.setText('CLOSE') + self.enlarged_table.imageTableExpandButton.setMinimumWidth(75) + self.enlarged_table.imageTableExpandButton.clicked.disconnect() + self.enlarged_table.imageTableExpandButton.clicked.connect( + self.close_expanded_table + ) + self.enlarged_table.show() + else: self.enlarged_table.show() @time_and_log diff --git a/src/minder3d/lib/sovInfoTablePanelWidget.py b/src/minder3d/lib/sovInfoTablePanelWidget.py index d4abd01..be35c6d 100644 --- a/src/minder3d/lib/sovInfoTablePanelWidget.py +++ b/src/minder3d/lib/sovInfoTablePanelWidget.py @@ -1,3 +1,4 @@ +import numpy as np from PySide6.QtWidgets import QTableWidget, QTableWidgetItem, QWidget from .sovUtils import time_and_log @@ -20,12 +21,10 @@ def __init__(self, gui, state, parent=None): self.gui = gui self.state = state - self.infoTableWidget.setRowCount(3) + self.pixel_info_row_start = 0 + + self.infoTableWidget.setSizeAdjustPolicy(QTableWidget.AdjustToContents) self.infoTableWidget.setColumnCount(2) - self.infoTableWidget.setItem(0, 0, QTableWidgetItem('Pixel Coordinate')) - self.infoTableWidget.setItem(1, 0, QTableWidgetItem(' Image Value')) - self.infoTableWidget.setItem(2, 0, QTableWidgetItem(' Overlay Value')) - self.infoTableWidget.setColumnWidth(1, 200) self.infoTableWidget.setEditTriggers(QTableWidget.NoEditTriggers) self.infoTableWidget.setSelectionMode(QTableWidget.NoSelection) self.infoTableWidget.setShowGrid(True) @@ -37,7 +36,44 @@ def __init__(self, gui, state, parent=None): @time_and_log def update_image(self): - pass + self.infoTableWidget.clear() + self.infoTableWidget.setRowCount(8) + self.infoTableWidget.setItem( + 0, 0, QTableWidgetItem('Image Information') + ) + img = self.state.image[self.state.current_image_num] + + self.infoTableWidget.setItem(1, 0, QTableWidgetItem(' Image Size')) + info_str = ', '.join( + [f'{x:0.1f}' for x in img.GetLargestPossibleRegion().GetSize()] + ) + self.infoTableWidget.setItem(1, 1, QTableWidgetItem(info_str)) + + self.infoTableWidget.setItem(2, 0, QTableWidgetItem(' Image Origin')) + info_str = ', '.join([f'{x:0.1f}' for x in img.GetOrigin()]) + self.infoTableWidget.setItem(2, 1, QTableWidgetItem(info_str)) + + self.infoTableWidget.setItem(3, 0, QTableWidgetItem(' Image Spacing')) + if img.GetSpacing()[0] > 1: + info_str = ', '.join([f'{x:0.1f}' for x in img.GetSpacing()]) + else: + info_str = ', '.join([f'{x:0.4f}' for x in img.GetSpacing()]) + self.infoTableWidget.setItem(3, 1, QTableWidgetItem(info_str)) + + self.infoTableWidget.setItem( + 4, 0, QTableWidgetItem(' Image Direction') + ) + info_str = ', '.join( + [f'{x:0.1f}' for x in np.array(img.GetDirection()).flatten()] + ) + self.infoTableWidget.setItem(4, 1, QTableWidgetItem(info_str)) + + self.pixel_info_row_start = 5 + self.infoTableWidget.setItem(5, 0, QTableWidgetItem('Pixel Coordinate')) + self.infoTableWidget.setItem(6, 0, QTableWidgetItem(' Image Value')) + self.infoTableWidget.setItem(7, 0, QTableWidgetItem(' Overlay Value')) + + self.infoTableWidget.resizeColumnsToContents() @time_and_log def update_pixel(self): @@ -54,7 +90,9 @@ def update_pixel(self): pos_str = ', '.join( [f'{x:0.1f}' for x in self.state.current_pixel_position] ) - self.infoTableWidget.setItem(0, 1, QTableWidgetItem(pos_str)) + self.infoTableWidget.setItem( + self.pixel_info_row_start, 1, QTableWidgetItem(pos_str) + ) if ( self.state.image[self.state.current_image_num] .GetLargestPossibleRegion() @@ -68,13 +106,25 @@ def update_pixel(self): - self.state.image_min[self.state.current_image_num] ) < 1: self.infoTableWidget.setItem( - 1, 1, QTableWidgetItem(f'{img_val:0.4f}') + self.pixel_info_row_start + 1, + 1, + QTableWidgetItem(f'{img_val:0.4f}'), ) else: self.infoTableWidget.setItem( - 1, 1, QTableWidgetItem(f'{img_val:0.1f}') + self.pixel_info_row_start + 1, + 1, + QTableWidgetItem(f'{img_val:0.1f}'), ) - self.infoTableWidget.setItem(2, 1, QTableWidgetItem('0')) + self.infoTableWidget.setItem( + self.pixel_info_row_start + 2, 1, QTableWidgetItem('0') + ) else: - self.infoTableWidget.setItem(1, 1, QTableWidgetItem('Outside')) - self.infoTableWidget.setItem(2, 1, QTableWidgetItem('Outside')) + self.infoTableWidget.setItem( + self.pixel_info_row_start + 1, 1, QTableWidgetItem('Outside') + ) + self.infoTableWidget.setItem( + self.pixel_info_row_start + 2, 1, QTableWidgetItem('Outside') + ) + + self.infoTableWidget.resizeColumnsToContents() diff --git a/src/minder3d/lib/sovObjectPanelWidget.py b/src/minder3d/lib/sovObjectPanelWidget.py index 95f7174..04ad2fa 100644 --- a/src/minder3d/lib/sovObjectPanelWidget.py +++ b/src/minder3d/lib/sovObjectPanelWidget.py @@ -86,6 +86,8 @@ def update_highlight_selected(self, value): """ self.state.highlight_selected = value for selected_id in self.state.selected_ids: + if selected_id == -1: + continue self.gui.log(f'update_highlight_selected: Id={selected_id}') so = self.state.scene_list[ self.state.scene_list_ids.index(selected_id) @@ -245,9 +247,12 @@ def rename_selected_object(self): def delete_selected_objects(self): """Delete the selected objects from the scene. - This function deletes the selected objects from the scene by removing them from the scene list and updating the GUI accordingly. + This function deletes the selected objects from the scene by removing + them from the scene list and updating the GUI accordingly. """ for so_id in self.state.selected_ids: + if so_id == -1: + continue scene_idx = self.state.scene_list_ids.index(so_id) so = self.state.scene_list[scene_idx] so_parent = so.GetParent() @@ -266,7 +271,7 @@ def delete_selected_objects(self): self.update_gui = True - self.update_scene() + self.gui.update_scene() @time_and_log def propogate_properties_to_all(self): @@ -285,7 +290,7 @@ def propogate_properties_to_all(self): for idx in range(len(self.state.scene_list)): self.state.scene_list_properties[idx]['ColorBy'] = color_by self.state.scene_list[idx].GetProperty().SetColor(color) - self.redraw_object(self.state.scene_list[idx]) + self.gui.redraw_object(self.state.scene_list[idx]) @time_and_log def propogate_properties_to_similar(self): diff --git a/src/minder3d/lib/sovOtsuLogic.py b/src/minder3d/lib/sovOtsuLogic.py index 498444f..08632d1 100644 --- a/src/minder3d/lib/sovOtsuLogic.py +++ b/src/minder3d/lib/sovOtsuLogic.py @@ -12,4 +12,5 @@ def run(self, inputImage, numberOfThresholds): filter = itk.OtsuMultipleThresholdsImageFilter.New(Input=inputImage) filter.SetNumberOfThresholds(numberOfThresholds) filter.Update() - return filter.GetOutput().astype(np.uint8) + img = filter.GetOutput().astype(np.uint8) + return img diff --git a/src/minder3d/lib/sovUtils.py b/src/minder3d/lib/sovUtils.py index 99febcf..07bfe05 100644 --- a/src/minder3d/lib/sovUtils.py +++ b/src/minder3d/lib/sovUtils.py @@ -222,6 +222,56 @@ def add_objects_in_mask_image_to_scene(mask_image, scene): scene.AddChild(mask_so) +@time_and_log +def compress_scene_for_saving(scene): + """Compresses a scene for saving. + + It compresses the input scene by removing unnecessary objects and compressing the scene. + + Args: + scene: The scene to be compressed. + Returns: + new_scene: A compressed copy of the scene. + """ + # HERE HERE HERE + mask_objects = get_children_as_list(scene, 'ImageMask') + print('Num mask objects = ', len(mask_objects)) + mask_image_pointers = list( + np.unique([id(mask.GetImage()) for mask in mask_objects]) + ) + print('Num mask object pointers = ', len(mask_image_pointers)) + print('Mask image pointers = ', mask_image_pointers) + for mask_object in mask_objects: + imgPntr = id(mask_object.GetImage()) + print('Mask object image pointer = ', imgPntr) + if imgPntr not in mask_image_pointers: + print('Removing mask object with image pointer = ', imgPntr) + # mask_object.GetParent().RemoveChild(mask_object) + else: + print('Keeping mask object with image pointer = ', imgPntr) + # mask_image_pointers.remove(id) + return scene + + +def uncompress_scene_after_loading(scene): + """Uncompresses a scene after loading. + + It uncompresses the input scene by adding necessary objects and uncompressing the scene. + + Args: + scene: The scene to be uncompressed. + Returns: + scene: The uncompressed scene. + """ + mask_objects = get_children_as_list(scene, 'ImageMask') + print('Num mask objects = ', len(mask_objects)) + for mask_object in mask_objects: + parent = mask_object.GetParent() + parent.RemoveChild(mask_object) + add_objects_in_mask_image_to_scene(mask_object.GetImage(), parent) + return scene + + @time_and_log def get_children_as_list( grp: itk.GroupSpatialObject, child_type: str = '' @@ -290,6 +340,7 @@ def read_group(filename: str, dims: int = 3) -> itk.GroupSpatialObject: try: groupFileReader = itk.SpatialObjectReader[dims].New() groupFileReader.SetFileName(filename) + groupFileReader.SetMetaIOVersion(1) groupFileReader.Update() except RuntimeError: return None @@ -314,4 +365,5 @@ def write_group(group: itk.GroupSpatialObject, filename: str): groupFileWriter = GroupFileWriterType.New() groupFileWriter.SetFileName(filename) groupFileWriter.SetInput(group) + groupFileWriter.SetMetaIOVersion(1) groupFileWriter.Update() diff --git a/src/minder3d/lib/sovView2DPanelWidget.py b/src/minder3d/lib/sovView2DPanelWidget.py index abe4ef3..c3727e3 100644 --- a/src/minder3d/lib/sovView2DPanelWidget.py +++ b/src/minder3d/lib/sovView2DPanelWidget.py @@ -299,13 +299,18 @@ def create_new_image(self): self.update_view_plane_coronal(redraw=False) elif view_plane == 1: self.update_view_plane_sagittal(redraw=False) - elif view_plane == 2: + else: # if view_plane == 2: self.update_view_plane_axial(redraw=False) # Sagittal axis is viewed in the negative direction - flip[self.state.view2D_csa_axis_order[-1][1]] = not flip[ - self.state.view2D_csa_axis_order[-1][1] - ] + # flip[self.state.view2D_csa_axis_order[-1][1]] = not flip[ + # self.state.view2D_csa_axis_order[-1][1] + # ] + # If coronal axis is data axis 2, then it is viewed in the negative direction + if self.state.view2D_csa_axis_order[-1][0] == 2: + flip[self.state.view2D_csa_axis_order[-1][0]] = not flip[ + self.state.view2D_csa_axis_order[-1][0] + ] self.state.view2D_flip.append(flip) @time_and_log @@ -457,6 +462,9 @@ def update_reset(self): @time_and_log def redraw_object(self, so): + if self.state.current_image_num < 0: + return + if ( self.state.highlight_selected and so.GetId() in self.state.selected_ids diff --git a/src/minder3d/lib/sovView2DPanelWidget.ui b/src/minder3d/lib/sovView2DPanelWidget.ui index 3faf00b..7958708 100644 --- a/src/minder3d/lib/sovView2DPanelWidget.ui +++ b/src/minder3d/lib/sovView2DPanelWidget.ui @@ -455,10 +455,16 @@ - 35 + 30 0 + + + 30 + 16777215 + + 7 diff --git a/src/minder3d/lib/sovView2DRenderWindowInteractor.py b/src/minder3d/lib/sovView2DRenderWindowInteractor.py index 5f60a2a..629fd60 100644 --- a/src/minder3d/lib/sovView2DRenderWindowInteractor.py +++ b/src/minder3d/lib/sovView2DRenderWindowInteractor.py @@ -35,9 +35,6 @@ def __init__(self, gui, state, parent=None): 7: 'Crop', } - self.state.view2D_image_axis_order = [0, 1, 2] - self.state.view2D_csa_axis_order = [2, 0, 1] - self.current_mouse_mode = 0 self.mouse_pressed = False diff --git a/src/minder3d/lib/sovView3DPanelWidget.ui b/src/minder3d/lib/sovView3DPanelWidget.ui index b3df03f..b6c4bdd 100644 --- a/src/minder3d/lib/sovView3DPanelWidget.ui +++ b/src/minder3d/lib/sovView3DPanelWidget.ui @@ -7,7 +7,7 @@ 0 0 410 - 467 + 522 @@ -35,54 +35,152 @@ - - - + + + + + + 0 + 0 + + + + + 100 + 12 + + 7 - - - Black - - - - - Grey - - - - - White - - - - - Blue-Grey - - + + 100 + + + 99 + + + Qt::Horizontal + - - + + Qt::Horizontal - - QSizePolicy::Fixed + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Image View + + + + + + + + 0 + 0 + + + + + 100 + 12 + + + + Qt::Horizontal + + + + + + + Qt::Horizontal - 50 + 80 20 - + + + + + 0 + 0 + + + + + 30 + 0 + + + + + 30 + 16777215 + + + + + 7 + + + + Reset + + + + + + + + 0 + 0 + + + + Color Shift + + + + + + + 0 + 0 + + + + + 75 + 0 + + 7 @@ -115,81 +213,42 @@ - Volume + Volume: CTA + + + + + - - + + - + 0 0 - - - 0 - 12 - - - - - 7 - - - - 100 - - - 99 - - - Qt::Horizontal + + Opacity - - + + Qt::Horizontal - - QSizePolicy::Fixed - - 50 + 40 20 - - - - - 0 - 0 - - - - - 35 - 0 - - - - - 7 - - - - Reset - - - diff --git a/src/minder3d/lib/sovView3DRenderWindowInteractor.py b/src/minder3d/lib/sovView3DRenderWindowInteractor.py index e6ec553..ec22e28 100644 --- a/src/minder3d/lib/sovView3DRenderWindowInteractor.py +++ b/src/minder3d/lib/sovView3DRenderWindowInteractor.py @@ -79,6 +79,7 @@ def update_scene(self): point_data = convert_scene_to_surfaces(self.state.scene) self.scene_renderer.RemoveAllViewProps() + self.scene_renderer.Render() for scene_idx, so in enumerate(self.state.scene_list): actor = vtkActor() color_by = self.state.scene_list_properties[scene_idx]['ColorBy'] @@ -98,6 +99,7 @@ def update_scene(self): mapper.ScalarVisibilityOn() actor.SetMapper(mapper) self.scene_renderer.AddActor(actor) + self.scene_renderer.Render() self.reset_camera() @time_and_log diff --git a/src/minder3d/lib/sovView3DUtils.py b/src/minder3d/lib/sovView3DUtils.py index 0ee58a5..fce1539 100644 --- a/src/minder3d/lib/sovView3DUtils.py +++ b/src/minder3d/lib/sovView3DUtils.py @@ -166,7 +166,7 @@ def convert_masks_to_surfaces(mask_list): num_masks = len(mask_list) mask_surfaces = [] if num_masks > 0: - for mask_num, mask in enumerate(mask_list): + for mask in mask_list: vtkmask = itk.vtk_image_from_image(mask.GetImage()) SN = vtkSurfaceNets3D() SN.SetInputData(vtkmask) diff --git a/src/minder3d/lib/sovVisualizationPanelWidget.ui b/src/minder3d/lib/sovVisualizationPanelWidget.ui index 90387d9..2a8fa19 100644 --- a/src/minder3d/lib/sovVisualizationPanelWidget.ui +++ b/src/minder3d/lib/sovVisualizationPanelWidget.ui @@ -214,8 +214,8 @@ 240 0 - 151 - 71 + 241 + 101 @@ -227,7 +227,7 @@ - 40 + 140 40 91 20 @@ -243,7 +243,7 @@ - 10 + 110 10 121 24 @@ -253,6 +253,54 @@ Update 3D Scene + + + + 110 + 66 + 121 + 24 + + + + + 9 + + + + + Black + + + + + Grey + + + + + White + + + + + Blue-Grey + + + + + + + 20 + 70 + 81 + 16 + + + + Background: + + diff --git a/src/minder3d/lib/sovWelcomePanelWidget.py b/src/minder3d/lib/sovWelcomePanelWidget.py index b21b471..bd2c348 100644 --- a/src/minder3d/lib/sovWelcomePanelWidget.py +++ b/src/minder3d/lib/sovWelcomePanelWidget.py @@ -1,4 +1,3 @@ -from PySide6.QtGui import QColor, QPalette from PySide6.QtWidgets import QWidget from .sovImportDICOMPanelWidget import ImportDICOMPanelWidget @@ -36,11 +35,6 @@ def __init__(self, gui, state, parent=None): ) self.welcomeSaveSceneButton.pressed.connect(self.gui.save_scene) - p = self.welcomeTextEdit.palette() - p.setColor(QPalette.Base, QColor(43, 43, 43)) - p.setColor(QPalette.Text, QColor(200, 200, 200)) - self.welcomeTextEdit.setPalette(p) - @time_and_log def add_import_DICOM_panel(self): """Add the Import DICOM panel to the GUI tab widget if necessary. diff --git a/src/minder3d/lib/sovWelcomePanelWidget.ui b/src/minder3d/lib/sovWelcomePanelWidget.ui index 8ab8715..438ce06 100644 --- a/src/minder3d/lib/sovWelcomePanelWidget.ui +++ b/src/minder3d/lib/sovWelcomePanelWidget.ui @@ -13,43 +13,11 @@ Form - + 20 10 - 301 - 131 - - - - true - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css"> -p, li { white-space: pre-wrap; } -hr { height: 1px; border-width: 0; } -li.unchecked::marker { content: "\2610"; } -li.checked::marker { content: "\2612"; } -</style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:700;">Welcome to Minder3D!</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To get started, load data using the buttons to the right, the list of registered data on the left, or the &quot;File&quot; menu at the top.</p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">You can also import DICOM data, which will open a new tab to gather the necessary information.</p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">To process your data, select a method from the &quot;New Task&quot; tab.</p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">If you have questions or suggestions, please visit</p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> <a href="https://github.com/aylward/Minder3D"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/aylward/Minder3D</span></a></p></body></html> - - - - - - 360 - 20 121 24 @@ -61,8 +29,8 @@ li.checked::marker { content: "\2612"; } - 360 - 110 + 20 + 70 121 24 @@ -74,8 +42,8 @@ li.checked::marker { content: "\2612"; } - 520 - 20 + 300 + 10 121 24 @@ -87,8 +55,8 @@ li.checked::marker { content: "\2612"; } - 520 - 80 + 160 + 10 121 24 @@ -100,8 +68,8 @@ li.checked::marker { content: "\2612"; } - 360 - 80 + 160 + 40 121 24 @@ -113,8 +81,8 @@ li.checked::marker { content: "\2612"; } - 520 - 50 + 440 + 40 121 24 @@ -126,8 +94,8 @@ li.checked::marker { content: "\2612"; } - 520 - 110 + 300 + 40 121 24 @@ -139,8 +107,8 @@ li.checked::marker { content: "\2612"; } - 360 - 50 + 440 + 10 121 24 diff --git a/src/minder3d/lib/ui_sovView2DPanelWidget.py b/src/minder3d/lib/ui_sovView2DPanelWidget.py index 2ef15ec..a33fd8f 100644 --- a/src/minder3d/lib/ui_sovView2DPanelWidget.py +++ b/src/minder3d/lib/ui_sovView2DPanelWidget.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- ################################################################################ -## Form generated from reading UI file 'sovView2DPanelWidgetYgHBrs.ui' +## Form generated from reading UI file 'sovView2DPanelWidgetbqcKAo.ui' ## ## Created by: Qt User Interface Compiler version 6.5.0 ## @@ -216,7 +216,8 @@ def setupUi(self, View2DPanelWidget): self.view2DResetButton.setObjectName(u"view2DResetButton") sizePolicy1.setHeightForWidth(self.view2DResetButton.sizePolicy().hasHeightForWidth()) self.view2DResetButton.setSizePolicy(sizePolicy1) - self.view2DResetButton.setMinimumSize(QSize(35, 0)) + self.view2DResetButton.setMinimumSize(QSize(30, 0)) + self.view2DResetButton.setMaximumSize(QSize(30, 16777215)) self.view2DResetButton.setFont(font) self.horizontalLayout.addWidget(self.view2DResetButton) diff --git a/src/minder3d/lib/ui_sovView3DPanelWidget.py b/src/minder3d/lib/ui_sovView3DPanelWidget.py index 0935c7a..3c45daf 100644 --- a/src/minder3d/lib/ui_sovView3DPanelWidget.py +++ b/src/minder3d/lib/ui_sovView3DPanelWidget.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- ################################################################################ -## Form generated from reading UI file 'sovView3DPanelWidgeteiJpxx.ui' +## Form generated from reading UI file 'sovView3DPanelWidgetsmQRpG.ui' ## ## Created by: Qt User Interface Compiler version 6.5.0 ## @@ -15,15 +15,15 @@ QFont, QFontDatabase, QGradient, QIcon, QImage, QKeySequence, QLinearGradient, QPainter, QPalette, QPixmap, QRadialGradient, QTransform) -from PySide6.QtWidgets import (QApplication, QComboBox, QHBoxLayout, QPushButton, - QSizePolicy, QSlider, QSpacerItem, QVBoxLayout, - QWidget) +from PySide6.QtWidgets import (QApplication, QComboBox, QGridLayout, QLabel, + QPushButton, QSizePolicy, QSlider, QSpacerItem, + QVBoxLayout, QWidget) class Ui_View3DPanelWidget(object): def setupUi(self, View3DPanelWidget): if not View3DPanelWidget.objectName(): View3DPanelWidget.setObjectName(u"View3DPanelWidget") - View3DPanelWidget.resize(410, 467) + View3DPanelWidget.resize(410, 522) self.verticalLayout = QVBoxLayout(View3DPanelWidget) self.verticalLayout.setSpacing(3) self.verticalLayout.setObjectName(u"verticalLayout") @@ -35,23 +35,68 @@ def setupUi(self, View3DPanelWidget): self.verticalLayout_2.addLayout(self.view3DLayout) - self.horizontalLayout_2 = QHBoxLayout() - self.horizontalLayout_2.setObjectName(u"horizontalLayout_2") - self.view3DBkgComboBox = QComboBox(View3DPanelWidget) - self.view3DBkgComboBox.addItem("") - self.view3DBkgComboBox.addItem("") - self.view3DBkgComboBox.addItem("") - self.view3DBkgComboBox.addItem("") - self.view3DBkgComboBox.setObjectName(u"view3DBkgComboBox") + self.gridLayout = QGridLayout() + self.gridLayout.setObjectName(u"gridLayout") + self.view3DColorShiftSlider = QSlider(View3DPanelWidget) + self.view3DColorShiftSlider.setObjectName(u"view3DColorShiftSlider") + sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.view3DColorShiftSlider.sizePolicy().hasHeightForWidth()) + self.view3DColorShiftSlider.setSizePolicy(sizePolicy) + self.view3DColorShiftSlider.setMinimumSize(QSize(100, 12)) font = QFont() font.setPointSize(7) - self.view3DBkgComboBox.setFont(font) + self.view3DColorShiftSlider.setFont(font) + self.view3DColorShiftSlider.setMaximum(100) + self.view3DColorShiftSlider.setValue(99) + self.view3DColorShiftSlider.setOrientation(Qt.Horizontal) + + self.gridLayout.addWidget(self.view3DColorShiftSlider, 1, 4, 1, 1) + + self.horizontalSpacer_3 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) + + self.gridLayout.addItem(self.horizontalSpacer_3, 1, 3, 1, 1) + + self.label = QLabel(View3DPanelWidget) + self.label.setObjectName(u"label") + sizePolicy1 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) + sizePolicy1.setHorizontalStretch(0) + sizePolicy1.setVerticalStretch(0) + sizePolicy1.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy1) + + self.gridLayout.addWidget(self.label, 0, 0, 1, 1) + + self.view3DOpacitySlicer = QSlider(View3DPanelWidget) + self.view3DOpacitySlicer.setObjectName(u"view3DOpacitySlicer") + sizePolicy.setHeightForWidth(self.view3DOpacitySlicer.sizePolicy().hasHeightForWidth()) + self.view3DOpacitySlicer.setSizePolicy(sizePolicy) + self.view3DOpacitySlicer.setMinimumSize(QSize(100, 12)) + self.view3DOpacitySlicer.setOrientation(Qt.Horizontal) + + self.gridLayout.addWidget(self.view3DOpacitySlicer, 1, 2, 1, 1) + + self.horizontalSpacer_2 = QSpacerItem(80, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) + + self.gridLayout.addItem(self.horizontalSpacer_2, 1, 5, 1, 1) + + self.view3DResetButton = QPushButton(View3DPanelWidget) + self.view3DResetButton.setObjectName(u"view3DResetButton") + sizePolicy.setHeightForWidth(self.view3DResetButton.sizePolicy().hasHeightForWidth()) + self.view3DResetButton.setSizePolicy(sizePolicy) + self.view3DResetButton.setMinimumSize(QSize(30, 0)) + self.view3DResetButton.setMaximumSize(QSize(30, 16777215)) + self.view3DResetButton.setFont(font) - self.horizontalLayout_2.addWidget(self.view3DBkgComboBox) + self.gridLayout.addWidget(self.view3DResetButton, 1, 6, 1, 1) - self.horizontalSpacer = QSpacerItem(50, 20, QSizePolicy.Fixed, QSizePolicy.Minimum) + self.label_3 = QLabel(View3DPanelWidget) + self.label_3.setObjectName(u"label_3") + sizePolicy1.setHeightForWidth(self.label_3.sizePolicy().hasHeightForWidth()) + self.label_3.setSizePolicy(sizePolicy1) - self.horizontalLayout_2.addItem(self.horizontalSpacer) + self.gridLayout.addWidget(self.label_3, 0, 4, 1, 1) self.view3DViewComboBox = QComboBox(View3DPanelWidget) self.view3DViewComboBox.addItem("") @@ -60,44 +105,28 @@ def setupUi(self, View3DPanelWidget): self.view3DViewComboBox.addItem("") self.view3DViewComboBox.addItem("") self.view3DViewComboBox.addItem("") + self.view3DViewComboBox.addItem("") self.view3DViewComboBox.setObjectName(u"view3DViewComboBox") + sizePolicy.setHeightForWidth(self.view3DViewComboBox.sizePolicy().hasHeightForWidth()) + self.view3DViewComboBox.setSizePolicy(sizePolicy) + self.view3DViewComboBox.setMinimumSize(QSize(75, 0)) self.view3DViewComboBox.setFont(font) - self.horizontalLayout_2.addWidget(self.view3DViewComboBox) + self.gridLayout.addWidget(self.view3DViewComboBox, 1, 0, 1, 1) - self.view3DOpacitySlider = QSlider(View3DPanelWidget) - self.view3DOpacitySlider.setObjectName(u"view3DOpacitySlider") - sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.view3DOpacitySlider.sizePolicy().hasHeightForWidth()) - self.view3DOpacitySlider.setSizePolicy(sizePolicy) - self.view3DOpacitySlider.setMinimumSize(QSize(0, 12)) - self.view3DOpacitySlider.setFont(font) - self.view3DOpacitySlider.setMaximum(100) - self.view3DOpacitySlider.setValue(99) - self.view3DOpacitySlider.setOrientation(Qt.Horizontal) + self.label_2 = QLabel(View3DPanelWidget) + self.label_2.setObjectName(u"label_2") + sizePolicy1.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth()) + self.label_2.setSizePolicy(sizePolicy1) - self.horizontalLayout_2.addWidget(self.view3DOpacitySlider) + self.gridLayout.addWidget(self.label_2, 0, 2, 1, 1) - self.horizontalSpacer_2 = QSpacerItem(50, 20, QSizePolicy.Fixed, QSizePolicy.Minimum) + self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum) - self.horizontalLayout_2.addItem(self.horizontalSpacer_2) - - self.view3DResetButton = QPushButton(View3DPanelWidget) - self.view3DResetButton.setObjectName(u"view3DResetButton") - sizePolicy1 = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) - sizePolicy1.setHorizontalStretch(0) - sizePolicy1.setVerticalStretch(0) - sizePolicy1.setHeightForWidth(self.view3DResetButton.sizePolicy().hasHeightForWidth()) - self.view3DResetButton.setSizePolicy(sizePolicy1) - self.view3DResetButton.setMinimumSize(QSize(35, 0)) - self.view3DResetButton.setFont(font) - - self.horizontalLayout_2.addWidget(self.view3DResetButton) + self.gridLayout.addItem(self.horizontalSpacer, 1, 1, 1, 1) - self.verticalLayout_2.addLayout(self.horizontalLayout_2) + self.verticalLayout_2.addLayout(self.gridLayout) self.verticalLayout.addLayout(self.verticalLayout_2) @@ -110,18 +139,17 @@ def setupUi(self, View3DPanelWidget): def retranslateUi(self, View3DPanelWidget): View3DPanelWidget.setWindowTitle(QCoreApplication.translate("View3DPanelWidget", u"Form", None)) - self.view3DBkgComboBox.setItemText(0, QCoreApplication.translate("View3DPanelWidget", u"Black", None)) - self.view3DBkgComboBox.setItemText(1, QCoreApplication.translate("View3DPanelWidget", u"Grey", None)) - self.view3DBkgComboBox.setItemText(2, QCoreApplication.translate("View3DPanelWidget", u"White", None)) - self.view3DBkgComboBox.setItemText(3, QCoreApplication.translate("View3DPanelWidget", u"Blue-Grey", None)) - + self.label.setText(QCoreApplication.translate("View3DPanelWidget", u"Image View", None)) + self.view3DResetButton.setText(QCoreApplication.translate("View3DPanelWidget", u"Reset", None)) + self.label_3.setText(QCoreApplication.translate("View3DPanelWidget", u"Color Shift", None)) self.view3DViewComboBox.setItemText(0, QCoreApplication.translate("View3DPanelWidget", u"None", None)) self.view3DViewComboBox.setItemText(1, QCoreApplication.translate("View3DPanelWidget", u"Axial", None)) self.view3DViewComboBox.setItemText(2, QCoreApplication.translate("View3DPanelWidget", u"Coronal", None)) self.view3DViewComboBox.setItemText(3, QCoreApplication.translate("View3DPanelWidget", u"Sagittal", None)) self.view3DViewComboBox.setItemText(4, QCoreApplication.translate("View3DPanelWidget", u"All Planes", None)) - self.view3DViewComboBox.setItemText(5, QCoreApplication.translate("View3DPanelWidget", u"Volume", None)) + self.view3DViewComboBox.setItemText(5, QCoreApplication.translate("View3DPanelWidget", u"Volume: CTA", None)) + self.view3DViewComboBox.setItemText(6, "") - self.view3DResetButton.setText(QCoreApplication.translate("View3DPanelWidget", u"Reset", None)) + self.label_2.setText(QCoreApplication.translate("View3DPanelWidget", u"Opacity", None)) # retranslateUi diff --git a/src/minder3d/lib/ui_sovVisualizationPanelWidget.py b/src/minder3d/lib/ui_sovVisualizationPanelWidget.py index eb1ff10..6e6987b 100644 --- a/src/minder3d/lib/ui_sovVisualizationPanelWidget.py +++ b/src/minder3d/lib/ui_sovVisualizationPanelWidget.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- ################################################################################ -## Form generated from reading UI file 'sovVisualizationPanelWidgetRPuXNj.ui' +## Form generated from reading UI file 'sovVisualizationPanelWidgetntFVpm.ui' ## ## Created by: Qt User Interface Compiler version 6.5.0 ## @@ -15,8 +15,9 @@ QFont, QFontDatabase, QGradient, QIcon, QImage, QKeySequence, QLinearGradient, QPainter, QPalette, QPixmap, QRadialGradient, QTransform) -from PySide6.QtWidgets import (QApplication, QCheckBox, QDoubleSpinBox, QFrame, - QLabel, QPushButton, QSizePolicy, QWidget) +from PySide6.QtWidgets import (QApplication, QCheckBox, QComboBox, QDoubleSpinBox, + QFrame, QLabel, QPushButton, QSizePolicy, + QWidget) class Ui_VisualizationPanelWidget(object): def setupUi(self, VisualizationPanelWidget): @@ -80,16 +81,27 @@ def setupUi(self, VisualizationPanelWidget): self.vizIntensityMaxLabel.setFont(font) self.viz3DFrame = QFrame(VisualizationPanelWidget) self.viz3DFrame.setObjectName(u"viz3DFrame") - self.viz3DFrame.setGeometry(QRect(240, 0, 151, 71)) + self.viz3DFrame.setGeometry(QRect(240, 0, 241, 101)) self.viz3DFrame.setFrameShape(QFrame.StyledPanel) self.viz3DFrame.setFrameShadow(QFrame.Raised) self.vizAutoUpdate3DSceneCheckBox = QCheckBox(self.viz3DFrame) self.vizAutoUpdate3DSceneCheckBox.setObjectName(u"vizAutoUpdate3DSceneCheckBox") - self.vizAutoUpdate3DSceneCheckBox.setGeometry(QRect(40, 40, 91, 20)) + self.vizAutoUpdate3DSceneCheckBox.setGeometry(QRect(140, 40, 91, 20)) self.vizAutoUpdate3DSceneCheckBox.setChecked(True) self.vizUpdate3DSceneButton = QPushButton(self.viz3DFrame) self.vizUpdate3DSceneButton.setObjectName(u"vizUpdate3DSceneButton") - self.vizUpdate3DSceneButton.setGeometry(QRect(10, 10, 121, 24)) + self.vizUpdate3DSceneButton.setGeometry(QRect(110, 10, 121, 24)) + self.vizView3DBackgroundComboBox = QComboBox(self.viz3DFrame) + self.vizView3DBackgroundComboBox.addItem("") + self.vizView3DBackgroundComboBox.addItem("") + self.vizView3DBackgroundComboBox.addItem("") + self.vizView3DBackgroundComboBox.addItem("") + self.vizView3DBackgroundComboBox.setObjectName(u"vizView3DBackgroundComboBox") + self.vizView3DBackgroundComboBox.setGeometry(QRect(110, 66, 121, 24)) + self.vizView3DBackgroundComboBox.setFont(font) + self.vizIntensityMinLabel_2 = QLabel(self.viz3DFrame) + self.vizIntensityMinLabel_2.setObjectName(u"vizIntensityMinLabel_2") + self.vizIntensityMinLabel_2.setGeometry(QRect(20, 70, 81, 16)) self.retranslateUi(VisualizationPanelWidget) @@ -107,5 +119,11 @@ def retranslateUi(self, VisualizationPanelWidget): self.vizIntensityMaxLabel.setText(QCoreApplication.translate("VisualizationPanelWidget", u"Max:", None)) self.vizAutoUpdate3DSceneCheckBox.setText(QCoreApplication.translate("VisualizationPanelWidget", u"Auto Update", None)) self.vizUpdate3DSceneButton.setText(QCoreApplication.translate("VisualizationPanelWidget", u"Update 3D Scene", None)) + self.vizView3DBackgroundComboBox.setItemText(0, QCoreApplication.translate("VisualizationPanelWidget", u"Black", None)) + self.vizView3DBackgroundComboBox.setItemText(1, QCoreApplication.translate("VisualizationPanelWidget", u"Grey", None)) + self.vizView3DBackgroundComboBox.setItemText(2, QCoreApplication.translate("VisualizationPanelWidget", u"White", None)) + self.vizView3DBackgroundComboBox.setItemText(3, QCoreApplication.translate("VisualizationPanelWidget", u"Blue-Grey", None)) + + self.vizIntensityMinLabel_2.setText(QCoreApplication.translate("VisualizationPanelWidget", u"Background:", None)) # retranslateUi diff --git a/src/minder3d/lib/ui_sovWelcomePanelWidget.py b/src/minder3d/lib/ui_sovWelcomePanelWidget.py index 8b63990..dcad4ea 100644 --- a/src/minder3d/lib/ui_sovWelcomePanelWidget.py +++ b/src/minder3d/lib/ui_sovWelcomePanelWidget.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- ################################################################################ -## Form generated from reading UI file 'sovWelcomePanelWidgetZDuWhr.ui' +## Form generated from reading UI file 'sovWelcomePanelWidgetkiiigT.ui' ## ## Created by: Qt User Interface Compiler version 6.5.0 ## @@ -15,42 +15,37 @@ QFont, QFontDatabase, QGradient, QIcon, QImage, QKeySequence, QLinearGradient, QPainter, QPalette, QPixmap, QRadialGradient, QTransform) -from PySide6.QtWidgets import (QApplication, QPushButton, QSizePolicy, QTextEdit, - QWidget) +from PySide6.QtWidgets import (QApplication, QPushButton, QSizePolicy, QWidget) class Ui_WelcomePanelWidget(object): def setupUi(self, WelcomePanelWidget): if not WelcomePanelWidget.objectName(): WelcomePanelWidget.setObjectName(u"WelcomePanelWidget") WelcomePanelWidget.resize(667, 153) - self.welcomeTextEdit = QTextEdit(WelcomePanelWidget) - self.welcomeTextEdit.setObjectName(u"welcomeTextEdit") - self.welcomeTextEdit.setGeometry(QRect(20, 10, 301, 131)) - self.welcomeTextEdit.setReadOnly(True) self.welcomeLoadImageButton = QPushButton(WelcomePanelWidget) self.welcomeLoadImageButton.setObjectName(u"welcomeLoadImageButton") - self.welcomeLoadImageButton.setGeometry(QRect(360, 20, 121, 24)) + self.welcomeLoadImageButton.setGeometry(QRect(20, 10, 121, 24)) self.welcomeImportDICOMButton = QPushButton(WelcomePanelWidget) self.welcomeImportDICOMButton.setObjectName(u"welcomeImportDICOMButton") - self.welcomeImportDICOMButton.setGeometry(QRect(360, 110, 121, 24)) + self.welcomeImportDICOMButton.setGeometry(QRect(20, 70, 121, 24)) self.welcomeSaveImageButton = QPushButton(WelcomePanelWidget) self.welcomeSaveImageButton.setObjectName(u"welcomeSaveImageButton") - self.welcomeSaveImageButton.setGeometry(QRect(520, 20, 121, 24)) + self.welcomeSaveImageButton.setGeometry(QRect(300, 10, 121, 24)) self.welcomeSaveSceneButton = QPushButton(WelcomePanelWidget) self.welcomeSaveSceneButton.setObjectName(u"welcomeSaveSceneButton") - self.welcomeSaveSceneButton.setGeometry(QRect(520, 80, 121, 24)) + self.welcomeSaveSceneButton.setGeometry(QRect(160, 10, 121, 24)) self.welcomeLoadSceneButton = QPushButton(WelcomePanelWidget) self.welcomeLoadSceneButton.setObjectName(u"welcomeLoadSceneButton") - self.welcomeLoadSceneButton.setGeometry(QRect(360, 80, 121, 24)) + self.welcomeLoadSceneButton.setGeometry(QRect(160, 40, 121, 24)) self.welcomeSaveOverlayButton = QPushButton(WelcomePanelWidget) self.welcomeSaveOverlayButton.setObjectName(u"welcomeSaveOverlayButton") - self.welcomeSaveOverlayButton.setGeometry(QRect(520, 50, 121, 24)) + self.welcomeSaveOverlayButton.setGeometry(QRect(440, 40, 121, 24)) self.welcomeSaveVTKModelsButton = QPushButton(WelcomePanelWidget) self.welcomeSaveVTKModelsButton.setObjectName(u"welcomeSaveVTKModelsButton") - self.welcomeSaveVTKModelsButton.setGeometry(QRect(520, 110, 121, 24)) + self.welcomeSaveVTKModelsButton.setGeometry(QRect(300, 40, 121, 24)) self.welcomeLoadOverlayButton = QPushButton(WelcomePanelWidget) self.welcomeLoadOverlayButton.setObjectName(u"welcomeLoadOverlayButton") - self.welcomeLoadOverlayButton.setGeometry(QRect(360, 50, 121, 24)) + self.welcomeLoadOverlayButton.setGeometry(QRect(440, 10, 121, 24)) self.retranslateUi(WelcomePanelWidget) @@ -59,25 +54,6 @@ def setupUi(self, WelcomePanelWidget): def retranslateUi(self, WelcomePanelWidget): WelcomePanelWidget.setWindowTitle(QCoreApplication.translate("WelcomePanelWidget", u"Form", None)) - self.welcomeTextEdit.setHtml(QCoreApplication.translate("WelcomePanelWidget", u"\n" -"\n" -"

Welcome to Minder3D!

\n" -"


\n" -"

To get started, load data using the buttons to the r" - "ight, the list of registered data on the left, or the "File" menu at the top.

\n" -"


\n" -"

You can also import DICOM data, which will open a new tab to gather the necessary information.

\n" -"


\n" -"

To process your data, select a method from the "New Task" tab.

\n" -"


\n" -"

If you have questions or suggestions, please visit

\n" -"

https://github.com/aylward/Minder3D

", None)) self.welcomeLoadImageButton.setText(QCoreApplication.translate("WelcomePanelWidget", u"Load Image", None)) self.welcomeImportDICOMButton.setText(QCoreApplication.translate("WelcomePanelWidget", u"Import DICOM Data", None)) self.welcomeSaveImageButton.setText(QCoreApplication.translate("WelcomePanelWidget", u"Save Image", None)) diff --git a/src/minder3d/minder3DWindow.py b/src/minder3d/minder3DWindow.py index 2258e77..1b3b421 100644 --- a/src/minder3d/minder3DWindow.py +++ b/src/minder3d/minder3DWindow.py @@ -1,6 +1,7 @@ import os import itk +import itk.itkGDCMImageIOPython import numpy as np import vtk from PySide6.QtCore import QCoreApplication, QFileInfo @@ -19,10 +20,12 @@ from .lib.sovUtils import ( LogWindow, add_objects_in_mask_image_to_scene, + compress_scene_for_saving, get_children_as_list, read_group, resample_overlay_to_match_image, time_and_log, + uncompress_scene_after_loading, write_group, ) from .lib.sovView2DPanelWidget import View2DPanelWidget @@ -50,7 +53,7 @@ def __init__(self, parent=None): self.log_window = LogWindow(self.state.logger) self.statusViewLogButton.pressed.connect(self.log_window.show) - self.log_window.logger.setLevel('INFO') + self.log_window.logger.setLevel('WARNING') self.state.scene.SetId(self.state.scene.GetNextAvailableId()) @@ -197,7 +200,16 @@ def load_image(self, filename=None): if self.file_dialog.exec() == QFileDialog.Accepted: filename = self.file_dialog.selectedFiles()[0] if filename is not None: - img = itk.imread(filename, self.state.image_pixel_type) + imageio = None + # info = QFileInfo(filename) + # if info.isDir(): + # print("It's DICOM!") + # imageio = itk.GDCMImageIO.New() + # imageio.LoadPrivateTagsOn() + img = itk.imread( + filename, self.state.image_pixel_type, imageio=imageio + ) + # print(img.GetMetaDataDictionary()) if img is None: self.log('Image could not be loaded.', 'error') return @@ -259,6 +271,7 @@ def load_scene(self, filename=None): self.log('Scene could not be loaded.', 'error') return + self.state.scene = uncompress_scene_after_loading(self.state.scene) self.update_scene() self.imageTablePanel.load_scene() @@ -365,7 +378,9 @@ def save_scene(self, filename=None): if filename: self.state.scene_filename = os.path.abspath(filename) self.log(f'Saving scene to {filename}') - write_group(self.state.scene, filename) + new_scene = compress_scene_for_saving(self.state.scene) + print(new_scene) + write_group(new_scene, filename) self.imageTablePanel.save_scene(filename) @time_and_log @@ -520,7 +535,6 @@ def update_scene(self): so.GetProperty().SetTagStringValue( 'Name', f'{so.GetTypeName()} {so.GetId()}' ) - print(so.GetProperty().GetTagStringValue('Name')) if self.state.view2D_overlay_auto_update: self.view2DPanel.update_scene() diff --git a/src/minder3d/minder3DWindow.ui b/src/minder3d/minder3DWindow.ui index fd662c7..2da554d 100644 --- a/src/minder3d/minder3DWindow.ui +++ b/src/minder3d/minder3DWindow.ui @@ -6,7 +6,7 @@ 0 0 - 1024 + 1274 675
@@ -153,20 +153,20 @@
- 0 + 2 true - Welcome + Load / Save Data - Visualization + Advanced Visualization @@ -290,7 +290,7 @@ 0 0 - 1024 + 1274 22
diff --git a/src/minder3d/ui_minder3DWindow.py b/src/minder3d/ui_minder3DWindow.py index efbbc06..407d559 100644 --- a/src/minder3d/ui_minder3DWindow.py +++ b/src/minder3d/ui_minder3DWindow.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- ################################################################################ -## Form generated from reading UI file 'minder3DWindowZcklJE.ui' +## Form generated from reading UI file 'minder3DWindownkNdyQ.ui' ## ## Created by: Qt User Interface Compiler version 6.5.0 ## @@ -25,7 +25,7 @@ class Ui_MainWindow(object): def setupUi(self, MainWindow): if not MainWindow.objectName(): MainWindow.setObjectName(u"MainWindow") - MainWindow.resize(1024, 675) + MainWindow.resize(1274, 675) MainWindow.setMinimumSize(QSize(1024, 0)) self.loadImageMenuItem = QAction(MainWindow) self.loadImageMenuItem.setObjectName(u"loadImageMenuItem") @@ -198,7 +198,7 @@ def setupUi(self, MainWindow): MainWindow.setCentralWidget(self.centralwidget) self.menubar = QMenuBar(MainWindow) self.menubar.setObjectName(u"menubar") - self.menubar.setGeometry(QRect(0, 0, 1024, 22)) + self.menubar.setGeometry(QRect(0, 0, 1274, 22)) self.fileMenu = QMenu(self.menubar) self.fileMenu.setObjectName(u"fileMenu") MainWindow.setMenuBar(self.menubar) @@ -214,7 +214,7 @@ def setupUi(self, MainWindow): self.retranslateUi(MainWindow) - self.tabWidget.setCurrentIndex(0) + self.tabWidget.setCurrentIndex(2) QMetaObject.connectSlotsByName(MainWindow) @@ -229,8 +229,8 @@ def retranslateUi(self, MainWindow): self.loadSceneMenuItem.setText(QCoreApplication.translate("MainWindow", u"Load Spatial Objects", None)) self.saveSceneMenuItem.setText(QCoreApplication.translate("MainWindow", u"Save Spatial Objects", None)) self.savePreProcessedOverlayMenuItem.setText(QCoreApplication.translate("MainWindow", u"Save Pre-Processed Overlay", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.welcomeTab), QCoreApplication.translate("MainWindow", u"Welcome", None)) - self.tabWidget.setTabText(self.tabWidget.indexOf(self.visualizationTab), QCoreApplication.translate("MainWindow", u"Visualization", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.welcomeTab), QCoreApplication.translate("MainWindow", u"Load / Save Data", None)) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.visualizationTab), QCoreApplication.translate("MainWindow", u"Advanced Visualization", None)) self.tabWidget.setTabText(self.tabWidget.indexOf(self.newTaskTab), QCoreApplication.translate("MainWindow", u"New Task", None)) self.statusLabel.setText(QCoreApplication.translate("MainWindow", u"Status:", None)) self.statusViewLogButton.setText(QCoreApplication.translate("MainWindow", u"View Log", None))