Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build_macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ jobs:
- name: Make installer
run: |
git clone https://github.com/dbouget/quickpkg.git
quickpkg/quickpkg dist/Raidionics.app --output Raidionics-1.3.1-macOS.pkg
cp -r Raidionics-1.3.1-macOS.pkg dist/Raidionics-1.3.1-macOS-x86_64.pkg
quickpkg/quickpkg dist/Raidionics.app --output Raidionics-1.3.2-macOS.pkg
cp -r Raidionics-1.3.2-macOS.pkg dist/Raidionics-1.3.2-macOS-x86_64.pkg

- name: Upload package
uses: actions/upload-artifact@v4
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build_macos_arm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ jobs:
- name: Make installer
run: |
git clone https://github.com/dbouget/quickpkg.git
quickpkg/quickpkg dist/Raidionics.app --output Raidionics-1.3.1-macOS.pkg
cp -r Raidionics-1.3.1-macOS.pkg dist/Raidionics-1.3.1-macOS-arm64.pkg
quickpkg/quickpkg dist/Raidionics.app --output Raidionics-1.3.2-macOS.pkg
cp -r Raidionics-1.3.2-macOS.pkg dist/Raidionics-1.3.2-macOS-arm64.pkg

- name: Upload package
uses: actions/upload-artifact@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build_ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ jobs:
cp -r dist/Raidionics assets/Raidionics_ubuntu/usr/local/bin
dpkg-deb --build --root-owner-group assets/Raidionics_ubuntu
ls -la
cp -r assets/Raidionics_ubuntu.deb dist/Raidionics-1.3.1-ubuntu.deb
cp -r assets/Raidionics_ubuntu.deb dist/Raidionics-1.3.2-ubuntu.deb

- name: Upload package
uses: actions/upload-artifact@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/build_windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ jobs:
- name: Make installer
run: |
makensis.exe assets/Raidionics.nsi
cp -r assets/Raidionics-1.3.1-win.exe dist/Raidionics-1.3.1-win.exe
cp -r assets/Raidionics-1.3.2-win.exe dist/Raidionics-1.3.2-win.exe

- name: Upload package
uses: actions/upload-artifact@v4
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
[![Paper](https://zenodo.org/badge/DOI/10.1038/s41598-023-42048-7.svg)](https://doi.org/10.1038/s41598-023-42048-7)
[![codecov](https://codecov.io/gh/raidionics/Raidionics/branch/master/graph/badge.svg?token=ZSPQVR7RKX)](https://codecov.io/gh/raidionics/Raidionics)
[![GitHub release](https://img.shields.io/github/v/release/raidionics/raidionics?sort=semver)](https://github.com/raidionics/raidionics/releases)
<a target="_blank" href="https://huggingface.co/spaces/dbouget/raidionics"><img src="https://img.shields.io/badge/🤗%20Hugging%20Face-Spaces-yellow.svg"></a>

**Raidionics** was developed by SINTEF Medical Image Analysis. A paper presenting the software and some benchmarks has been published in [Scientific Reports](https://doi.org/10.1038/s41598-023-42048-7).

Expand Down
4 changes: 2 additions & 2 deletions assets/Raidionics.nsi
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
!define APP_NAME "Raidionics"
!define COMP_NAME "SINTEF"
!define VERSION "1.3.1"
!define VERSION "1.3.2"
!define DESCRIPTION "Application"
!define INSTALLER_NAME "Raidionics-1.3.1-win.exe"
!define INSTALLER_NAME "Raidionics-1.3.2-win.exe"
!define MAIN_APP_EXE "Raidionics.exe"
!define INSTALL_TYPE "SetShellVarContext current"
!define REG_ROOT "HKLM"
Expand Down
2 changes: 1 addition & 1 deletion assets/main.spec
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ if sys.platform == "darwin":
'CFBundleIdentifier': 'Raidionics',
'CFBundleInfoDictionaryVersion': '6.0',
'CFBundleName': 'Raidionics',
'CFBundleVersion': '1.3.1',
'CFBundleVersion': '1.3.2',
'CFBundlePackageType': 'APPL',
'LSBackgroundOnly': 'false',
},
Expand Down
2 changes: 1 addition & 1 deletion assets/main_arm.spec
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ if sys.platform == "darwin":
'CFBundleIdentifier': 'Raidionics',
'CFBundleInfoDictionaryVersion': '6.0',
'CFBundleName': 'Raidionics',
'CFBundleVersion': '1.3.1',
'CFBundleVersion': '1.3.2',
'CFBundlePackageType': 'APPL',
'LSBackgroundOnly': 'false',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -414,13 +414,23 @@ def on_standardized_report_imported(self, report_uid: str) -> None:
report = None
report = TumorCharacteristicsWidget(patient_uid=self.uid, report_uid=report_uid, structure_name=c)
report_visible_name = f"Features: {c} - {report_structure.timestamp_folder_name}"
ritems = [self.results_selector_combobox.itemText(i) for i in range(self.results_selector_combobox.count())]

if report:
self.report_widgets[report_uid] = report
self.results_display_stackedwidget.addWidget(report)
self.results_selector_combobox.addItem(report_visible_name)
report.resizeRequested.connect(self.resizeRequested)
self.resizeRequested.emit()
if not report:
return

if report_visible_name in ritems:
rind = self.results_selector_combobox.findText(report_visible_name)
dkey = list(self.report_widgets.keys())[rind]
self.results_display_stackedwidget.removeWidget(self.report_widgets[dkey])
self.report_widgets[dkey].deleteLater()
self.report_widgets.pop(dkey)

self.report_widgets[report_uid] = report
self.results_display_stackedwidget.addWidget(report)
self.results_selector_combobox.addItem(report_visible_name)
report.resizeRequested.connect(self.resizeRequested)
self.resizeRequested.emit()

def on_size_request(self):
self.resizeRequested.emit()
5 changes: 3 additions & 2 deletions gui/UtilsWidgets/CustomQDialog/ResearchCommunityDialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ def __set_interface(self):

self.brats_widget = HospitalContributorWidget(self)
self.brats_widget.set_hospital_name("The BraTS challenge 2023/2024")
self.brats_widget.set_hospital_participants("""<a href=https://www.synapse.org/Synapse:syn64153130/wiki/>Official website</a>""")
self.brats_widget.set_hospital_participants("""<a href="https://www.synapse.org/Synapse:syn64153130/wiki">Official website</a>""")
self.brats_widget.set_logo_icon(os.path.join(os.path.dirname(os.path.realpath(__file__)),
'../../Images/brats-challenge-logo.png'))
self.main_scrollarea_layout.addWidget(self.brats_widget, 5, 0, 1, 1)
Expand Down Expand Up @@ -237,7 +237,8 @@ def __set_interface(self):
self.hospital_name_label = QLabel()
self.hospital_name_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
self.hospital_participants_label = QLabel()
self.hospital_participants_label.setTextInteractionFlags(Qt.TextSelectableByMouse)
self.hospital_participants_label.setTextInteractionFlags(Qt.TextSelectableByMouse | Qt.TextBrowserInteraction)
self.hospital_participants_label.setOpenExternalLinks(True)

self.hospital_location_layout = QVBoxLayout()
self.hospital_location_layout.setSpacing(0)
Expand Down
4 changes: 2 additions & 2 deletions utils/backend_logic.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,15 +257,15 @@ def generate_surrogate_folder(patient_parameters: PatientParameters, output_fold
for anno in manual_annos:
shutil.copyfile(src=patient_parameters.get_annotation_by_uid(anno).usable_input_filepath,
dst=os.path.join(surrogate_folder, "T" + str(ts_object.order), os.path.basename(
patient_parameters.get_mri_by_uid(im).usable_input_filepath[:-7] + '-label_' + str(c) + '.nii.gz')))
patient_parameters.get_mri_by_uid(im).usable_input_filepath[:-7] + '-label_' + c.name + '.nii.gz')))
else:
annos = patient_parameters.get_specific_annotations_for_mri(mri_volume_uid=im,
generation_type=AnnotationGenerationType.Automatic,
annotation_class=c)
for anno in annos:
shutil.copyfile(src=patient_parameters.get_annotation_by_uid(anno).usable_input_filepath,
dst=os.path.join(surrogate_folder, "T" + str(ts_object.order), os.path.basename(
patient_parameters.get_mri_by_uid(im).usable_input_filepath[:-7] + '-label_' + str(c) + '.nii.gz')))
patient_parameters.get_mri_by_uid(im).usable_input_filepath[:-7] + '-label_' + c.name + '.nii.gz')))

except Exception:
logging.error('Pipeline surrogate folder creation failed with: \n{}'.format(traceback.format_exc()))
Expand Down
1 change: 1 addition & 0 deletions utils/data_structures/AnnotationStructure.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class AnnotationClassType(Enum):
Cavity = 4, 'Cavity'
TumorCE = 5, 'Contrast-Enhancing Tumor'
WT = 6, 'Whole Tumor' # Corresponds to the sum of the tumor-CE, necrosis, and edema
Edema = 7, 'Surrounding non-enhancing FLAIR changes'
# @TODO. Is FLAIRChanges the whole tumor and should we support an edema category in addition?

Lungs = 100, 'Lungs'
Expand Down
8 changes: 8 additions & 0 deletions utils/data_structures/PatientParametersStructure.py
Original file line number Diff line number Diff line change
Expand Up @@ -949,6 +949,14 @@ def get_all_annotation_uids_for_radiological_volume(self, radiological_uid: str)
res.append(im)
return res

def get_all_reports_for_mri_and_type(self, mri_volume_uid: str, report_type: str) -> List[ReportingStructure]:
res = []
for r in list(self._reportings.keys()):
if (self._reportings[r].parent_mri_uid == mri_volume_uid and
self._reportings[r].get_report_task_str() == report_type):
res.append(self._reportings[r])
return res

def get_all_atlases_for_mri(self, mri_volume_uid: str) -> List[str]:
"""
Convenience method for collecting all atlas objects linked to a specific MRI volume.
Expand Down
44 changes: 44 additions & 0 deletions utils/logic/PipelineCreationHandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,17 @@ def __create_preop_segmentation_pipeline(tumor_type: str) -> dict:
pip[pip_num]["description"] = "Identifying the best necrosis segmentation model for existing inputs"
download_model(model_name='MRI_Necrosis')

pip_num_int = pip_num_int + 1
pip_num = str(pip_num_int)
pip[pip_num] = {}
pip[pip_num]["task"] = 'Model selection'
pip[pip_num]["model"] = 'MRI_SNFH'
pip[pip_num]["timestamp"] = 0
pip[pip_num]["format"] = "thresholding"
pip[pip_num]["description"] = ("Identifying the best surrounding non-enhancing FLAIR hyperintensity (SNFH) "
"segmentation model for existing inputs")
download_model(model_name='MRI_SNFH')

pip_num_int = pip_num_int + 1
pip_num = str(pip_num_int)
pip[pip_num] = {}
Expand Down Expand Up @@ -238,6 +249,17 @@ def __create_postop_segmentation_pipeline(tumor_type: str) -> dict:
pip[pip_num]["description"] = "Identifying the best rest enhancing tumor segmentation model for existing inputs"
download_model(model_name='MRI_TumorCE_Postop')

pip_num_int = pip_num_int + 1
pip_num = str(pip_num_int)
pip[pip_num] = {}
pip[pip_num]["task"] = 'Model selection'
pip[pip_num]["model"] = 'MRI_SNFH'
pip[pip_num]["timestamp"] = postop_ts
pip[pip_num]["format"] = "thresholding"
pip[pip_num]["description"] = ("Identifying the best surrounding non-enhancing FLAIR hyperintensity (SNFH) "
"segmentation model for existing inputs")
download_model(model_name='MRI_SNFH')

pip_num_int = pip_num_int + 1
pip_num = str(pip_num_int)
pip[pip_num] = {}
Expand Down Expand Up @@ -312,6 +334,17 @@ def __create_preop_reporting_pipeline(tumor_type: str) -> dict:
pip[pip_num]["description"] = "Identifying the best necrosis segmentation model for existing inputs"
download_model(model_name='MRI_Necrosis')

pip_num_int = pip_num_int + 1
pip_num = str(pip_num_int)
pip[pip_num] = {}
pip[pip_num]["task"] = 'Model selection'
pip[pip_num]["model"] = 'MRI_SNFH'
pip[pip_num]["timestamp"] = 0
pip[pip_num]["format"] = "thresholding"
pip[pip_num]["description"] = ("Identifying the best surrounding non-enhancing FLAIR hyperintensity (SNFH) "
"segmentation model for existing inputs")
download_model(model_name='MRI_SNFH')

pip_num_int = pip_num_int + 1
pip_num = str(pip_num_int)
pip[pip_num] = {}
Expand Down Expand Up @@ -362,6 +395,17 @@ def __create_postop_reporting_pipeline(tumor_type: str) -> dict:
pip[pip_num]["description"] = "Identifying the best tumor core segmentation model for existing inputs"
download_model(model_name='MRI_TumorCE_Postop')

pip_num_int = pip_num_int + 1
pip_num = str(pip_num_int)
pip[pip_num] = {}
pip[pip_num]["task"] = 'Model selection'
pip[pip_num]["model"] = 'MRI_SNFH'
pip[pip_num]["timestamp"] = postop_ts
pip[pip_num]["format"] = "thresholding"
pip[pip_num]["description"] = ("Identifying the best surrounding non-enhancing FLAIR hyperintensity (SNFH) "
"segmentation model for existing inputs")
download_model(model_name='MRI_SNFH')

pip_num_int = pip_num_int + 1
pip_num = str(pip_num_int)
pip[pip_num] = {}
Expand Down
34 changes: 25 additions & 9 deletions utils/logic/PipelineResultsCollector.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pandas as pd
import glob

from tmp_dependencies.utils.data_structures.ReportingStructure import ReportingType
from utils.data_structures.UserPreferencesStructure import UserPreferencesStructure
from utils.data_structures.MRIVolumeStructure import MRISequenceType
from utils.data_structures.AnnotationStructure import AnnotationClassType, AnnotationGenerationType
Expand Down Expand Up @@ -414,11 +415,19 @@ def collect_results(patient_parameters, pipeline):
report_filename = os.path.join(patient_parameters.output_folder, 'reporting', 'reporting',
"T" + str(timestamp), 'neuro_clinical_report.json')

# @TODO. Hard-coded for contrast-enhanced, will have to make it adjustable (should the base image be
# returned from the backend?
# parent_mri_uid = patient_parameters.get_all_mri_volumes_for_timestamp(timestamp_uid=patient_parameters.get_timestamp_by_order(order=timestamp).unique_id)
parent_mri_uid = patient_parameters.get_all_mri_volumes_for_sequence_type_and_timestamp(sequence_type=MRISequenceType.T1c,
timestamp_order=timestamp)
parent_mri_uid = []
if pip_step["tumor_type"] == "contrast-enhancing":
parent_mri_uid = patient_parameters.get_all_mri_volumes_for_sequence_type_and_timestamp(
sequence_type=MRISequenceType.T1c,
timestamp_order=timestamp)
elif pip_step["tumor_type"] == "non contrast-enhancing":
# @TODO. In the future, it might be T2 is the base image, should be adjustable?
parent_mri_uid = patient_parameters.get_all_mri_volumes_for_sequence_type_and_timestamp(
sequence_type=MRISequenceType.FLAIR,
timestamp_order=timestamp)
else:
logging.warning(f"[PipelineResultsCollector] Use-case not handled for updating a timestamp report"
f" for the following tumor type:{pip_step['tumor_type']}.")
if len(parent_mri_uid) == 0:
continue
parent_mri_uid = parent_mri_uid[0]
Expand All @@ -442,10 +451,17 @@ def collect_results(patient_parameters, pipeline):
shutil.move(report_filename_txt, dest_file_txt)

if os.path.exists(dest_file): # Should always exist
report_uid, error_msg = patient_parameters.import_report(dest_file, dest_ts_object.unique_id)
#@TODO. Maybe the reporting type could be named differently?
patient_parameters.reportings[report_uid].set_reporting_type("Tumor characteristics")
patient_parameters.reportings[report_uid].parent_mri_uid = parent_mri_uid
# If a report was previously computed, it should simply be updated
existing_reports = patient_parameters.get_all_reports_for_mri_and_type(mri_volume_uid=parent_mri_uid,
report_type=str(ReportingType.Features))
if len(existing_reports) == 0:
report_uid, error_msg = patient_parameters.import_report(dest_file, dest_ts_object.unique_id)
patient_parameters.reportings[report_uid].set_reporting_type("Tumor characteristics")
patient_parameters.reportings[report_uid].parent_mri_uid = parent_mri_uid
else:
# @TODO. It shouldn't be allowed with more than 1, have to improve!
existing_report = existing_reports[0]
report_uid = existing_report.unique_id
results['Report'].append(report_uid)
elif pip_step["task"] == "Surgical reporting":
report_filename = os.path.join(patient_parameters.output_folder, 'reporting', 'reporting',
Expand Down
Loading