Skip to content

Commit

Permalink
ENH: Add unicode for checkboxes and framework for TotalSegmentator
Browse files Browse the repository at this point in the history
  • Loading branch information
aylward committed Aug 5, 2024
1 parent 2e8f8ec commit 7dd304c
Show file tree
Hide file tree
Showing 23 changed files with 553 additions and 298 deletions.
45 changes: 12 additions & 33 deletions src/minder3d/lib/sovImageTablePanelWidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,12 @@
from PySide6.QtWidgets import (
QHeaderView,
QInputDialog,
QStyle,
QTableWidget,
QTableWidgetItem,
QWidget,
)

from .sovImageTableSettings import ImageTableSettings
from .sovImportExportPanelWidget import ImportExportPanelWidget
from .sovUtils import time_and_log
from .ui_sovImageTablePanelWidget import Ui_ImageTablePanelWidget

Expand All @@ -40,8 +38,6 @@ def __init__(self, gui, state, parent=None):
self.settings = ImageTableSettings()

self.selected = []
pixmapi = getattr(QStyle, 'SP_DialogApplyButton')
self.selected_icon = self.style().standardIcon(pixmapi)

self.imageTableWidget.setRowCount(0)
self.imageTableWidget.setColumnCount(8)
Expand Down Expand Up @@ -93,24 +89,7 @@ def __init__(self, gui, state, parent=None):

@time_and_log
def add_import_export_panel(self):
"""Add an image processing panel to the GUI if it does not already exist.
If the image processing panel does not exist, it creates a new ImageProcessPanelWidget and adds it to the tab widget.
If the image processing panel already exists, it sets the current widget to the existing panel.
Args:
self (object): The current instance of the class.
"""
if self.gui.importExportPanel is None:
self.gui.importExportPanel = ImportExportPanelWidget(
self.gui, self.state
)
if self.gui.tabWidget.indexOf(self.gui.importExportPanel) == -1:
indx = self.gui.tabWidget.indexOf(self.gui.newTaskTab)
self.gui.tabWidget.insertTab(
indx, self.gui.importExportPanel, 'Import/Save/Export'
)
self.gui.tabWidget.setCurrentWidget(self.gui.importExportPanel)
self.gui.tabWidget.setCurrentWidget(self.gui.importExportTab)

@time_and_log
def unload_selected(self):
Expand Down Expand Up @@ -202,21 +181,21 @@ def redraw_image_row(self, row_num):
col_num = 0
if row_num in self.selected:
self.imageTableWidget.setItem(
row_num, col_num, QTableWidgetItem(self.selected_icon, '')
row_num, col_num, QTableWidgetItem('\u25a3')
)
else:
self.imageTableWidget.setItem(
row_num, col_num, QTableWidgetItem('')
row_num, col_num, QTableWidgetItem('\u25a1')
)
col_num += 1
if img_num < len(self.state.image_filename):
self.imageTableWidget.setItem(
row_num, col_num, QTableWidgetItem(self.selected_icon, '')
row_num, col_num, QTableWidgetItem('\u25a3')
)
else:
print('ERROR: Can only redraw rows for images that are loaded.')
self.imageTableWidget.setItem(
row_num, col_num, QTableWidgetItem('')
row_num, col_num, QTableWidgetItem('\u25a1')
)
col_num += 1
self.imageTableWidget.setItem(
Expand Down Expand Up @@ -262,15 +241,15 @@ def redraw_scene_row(self, row_num):
col_num = 0
if row_num in self.selected:
self.imageTableWidget.setItem(
row_num, col_num, QTableWidgetItem(self.selected_icon, '')
row_num, col_num, QTableWidgetItem('\u25a3')
)
else:
self.imageTableWidget.setItem(
row_num, col_num, QTableWidgetItem('')
row_num, col_num, QTableWidgetItem('\u25a1')
)
col_num += 1
self.imageTableWidget.setItem(
row_num, col_num, QTableWidgetItem(self.selected_icon, '')
row_num, col_num, QTableWidgetItem('\u25a3')
)
col_num += 1
self.imageTableWidget.setItem(
Expand Down Expand Up @@ -350,11 +329,11 @@ def fill_table(self):
self.imageTableWidget.setItem(
row_num,
col_num,
QTableWidgetItem(self.selected_icon, ''),
QTableWidgetItem('\u25a3'),
)
else:
self.imageTableWidget.setItem(
row_num, col_num, QTableWidgetItem('')
row_num, col_num, QTableWidgetItem('\u25a1')
)
col_num += 1
loaded_text = ' '
Expand Down Expand Up @@ -402,11 +381,11 @@ def fill_table(self):
self.imageTableWidget.setItem(
row_num,
col_num,
QTableWidgetItem(self.selected_icon, ''),
QTableWidgetItem('\u25a3'),
)
else:
self.imageTableWidget.setItem(
row_num, col_num, QTableWidgetItem('')
row_num, col_num, QTableWidgetItem('\u25a1')
)
col_num += 1
loaded_text = ' '
Expand Down
1 change: 1 addition & 0 deletions src/minder3d/lib/sovImageTableSettings.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ def get_thumbnail_pixmap_from_vtk_image(self, img):
np_array = vtk_to_numpy(vtk_array)
dims = img.GetDimensions()
np_array = np_array.reshape(dims[1], dims[0], dims[2], -1)
np_array = np_array[::-1, :, :, :]

# Process the NumPy array
if np_array.shape[3] == 1:
Expand Down
33 changes: 25 additions & 8 deletions src/minder3d/lib/sovImportDICOMPanelWidget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,11 @@
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;meta charset=&quot;utf-8&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
hr { height: 1px; border-width: 0; }
li.unchecked::marker { content: &quot;\2610&quot;; }
li.checked::marker { content: &quot;\2612&quot;; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-weight:700;&quot;&gt;Import DICOM&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Select an input directory that contains the DICOM objects. That input directory and its subdirectories will be searched for DICOM objects that can be converted to images.&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Select an output directory for storing the converted images. A hierarchy of subdirectories will be automatically created that correspond to the &amp;lt;PatientName&amp;gt;/&amp;lt;StudyID&amp;gt;-&amp;lt;StudyDescription&amp;gt;-&amp;lt;StudyDate&amp;gt;/&amp;lt;Modality&amp;gt;/&amp;lt;SeriesNumber&amp;gt;-&amp;lt;SeriesDescription&amp;gt;-&amp;lt;InstanceNumber&amp;gt;.dcm&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Optionally, the data can be automatically registered with Minder3D and made available for one-click loading via the image browser table.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Segoe UI'; font-weight:700;&quot;&gt;Import DICOM&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Segoe UI';&quot;&gt;Select an input directory that contains the DICOM objects. That input directory and its subdirectories will be searched for DICOM objects that can be converted to images.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Segoe UI';&quot;&gt;Select an output directory for storing the converted images. A hierarchy of subdirectories will be automatically created that correspond to the &amp;lt;PatientName&amp;gt;/&amp;lt;StudyID&amp;gt;-&amp;lt;StudyDescription&amp;gt;-&amp;lt;StudyDate&amp;gt;/&amp;lt;Modality&amp;gt;/&amp;lt;SeriesNumber&amp;gt;-&amp;lt;SeriesDescription&amp;gt;-&amp;lt;InstanceNumber&amp;gt;.dcm&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot; margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Segoe UI';&quot;&gt;Optionally, the data can be automatically registered with Minder3D and made available for one-click loading via the image browser table.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
<widget class="QLineEdit" name="importDICOMInputDirectoryLineEdit">
Expand All @@ -58,6 +55,11 @@ li.checked::marker { content: &quot;\2612&quot;; }
<height>16</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>7</pointsize>
</font>
</property>
<property name="text">
<string>Input Directory:</string>
</property>
Expand Down Expand Up @@ -117,6 +119,11 @@ li.checked::marker { content: &quot;\2612&quot;; }
<height>16</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>7</pointsize>
</font>
</property>
<property name="text">
<string>Output Directory:</string>
</property>
Expand All @@ -130,6 +137,11 @@ li.checked::marker { content: &quot;\2612&quot;; }
<height>20</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>7</pointsize>
</font>
</property>
<property name="text">
<string>Automatically register</string>
</property>
Expand All @@ -143,6 +155,11 @@ li.checked::marker { content: &quot;\2612&quot;; }
<height>24</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>7</pointsize>
</font>
</property>
<property name="text">
<string>Run</string>
</property>
Expand Down
40 changes: 40 additions & 0 deletions src/minder3d/lib/sovImportExportPanelWidget.ui
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
<height>24</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>7</pointsize>
</font>
</property>
<property name="text">
<string>Load Image</string>
</property>
Expand All @@ -35,6 +40,11 @@
<height>24</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>7</pointsize>
</font>
</property>
<property name="text">
<string>Import DICOM Data</string>
</property>
Expand All @@ -48,6 +58,11 @@
<height>24</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>7</pointsize>
</font>
</property>
<property name="text">
<string>Save Image</string>
</property>
Expand All @@ -61,6 +76,11 @@
<height>24</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>7</pointsize>
</font>
</property>
<property name="text">
<string>Save Scene</string>
</property>
Expand All @@ -74,6 +94,11 @@
<height>24</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>7</pointsize>
</font>
</property>
<property name="text">
<string>Load Scene</string>
</property>
Expand All @@ -87,6 +112,11 @@
<height>24</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>7</pointsize>
</font>
</property>
<property name="text">
<string>Save Overlay</string>
</property>
Expand All @@ -100,6 +130,11 @@
<height>24</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>7</pointsize>
</font>
</property>
<property name="text">
<string>Save VTK Models</string>
</property>
Expand All @@ -113,6 +148,11 @@
<height>24</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>7</pointsize>
</font>
</property>
<property name="text">
<string>Load Overlay</string>
</property>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from .sovUtils import time_and_log


class LungCTALogic:
class IndexedOrgansLogic:
def __init__(self):
self.ai_first_run = True
self.image = None
Expand Down Expand Up @@ -116,9 +116,7 @@ def run(self):
nifti_nib = nib.Nifti1Image(
np.transpose(pre_array, (2, 1, 0)).copy(), mat
)
seg_nib = totalsegmentator(
input=nifti_nib, output=None, task='lung_vessels'
)
seg_nib = totalsegmentator(input=nifti_nib, output=None, task='total')

seg_array = seg_nib.get_fdata().astype(np.uint8)
seg_image = itk.GetImageFromArray(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
from PySide6.QtWidgets import QMessageBox, QWidget

from .sovLungCTALogic import LungCTALogic
from .sovIndexedOrgansLogic import IndexedOrgansLogic
from .sovUtils import add_objects_in_mask_image_to_scene, time_and_log
from .ui_sovLungCTAPanelWidget import Ui_LungCTAPanelWidget
from .ui_sovIndexedOrgansPanelWidget import Ui_IndexedOrgansPanelWidget


class LungCTAPanelWidget(QWidget, Ui_LungCTAPanelWidget):
class IndexedOrgansPanelWidget(QWidget, Ui_IndexedOrgansPanelWidget):
def __init__(self, gui, state, parent=None):
"""Initialize the LungCTA application.
"""Initialize the IndexedOrgans application.
Args:
gui: The graphical user interface object.
Expand All @@ -20,12 +20,12 @@ def __init__(self, gui, state, parent=None):

self.gui = gui
self.state = state
self.logic = LungCTALogic()
self.logic = IndexedOrgansLogic()

self.ai_first_run = True

self.lungStep1Button.clicked.connect(self.segment_ai)
self.lungStep1Button.setStyleSheet('background-color: #00aa00')
self.indexedOrgansStep1Button.clicked.connect(self.segment_ai)
self.indexedOrgansStep1Button.setStyleSheet('background-color: #00aa00')

@time_and_log
def segment_ai(self):
Expand Down
37 changes: 37 additions & 0 deletions src/minder3d/lib/sovIndexedOrgansPanelWidget.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>IndexedOrgansPanelWidget</class>
<widget class="QWidget" name="IndexedOrgansPanelWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>390</width>
<height>125</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QPushButton" name="indexedOrgansStep1Button">
<property name="geometry">
<rect>
<x>10</x>
<y>30</y>
<width>261</width>
<height>24</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>7</pointsize>
</font>
</property>
<property name="text">
<string>Run Total Segmentator</string>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>
Loading

0 comments on commit 7dd304c

Please sign in to comment.