Skip to content

61 feat implement and integrate analysis loading screen into ceus workflow#66

Open
OmidChaghaneh wants to merge 67 commits into
mainfrom
61-feat-implement-and-integrate-analysis-loading-screen-into-ceus-workflow
Open

61 feat implement and integrate analysis loading screen into ceus workflow#66
OmidChaghaneh wants to merge 67 commits into
mainfrom
61-feat-implement-and-integrate-analysis-loading-screen-into-ceus-workflow

Conversation

@OmidChaghaneh
Copy link
Copy Markdown
Contributor

No description provided.

akannan05 and others added 30 commits December 18, 2025 14:18
- Add 'Load DICOM File' button in ROI selection menu
- Implement file dialog for DICOM selection
- Add transparency slider with 0-100% control
- 0% shows pure B-mode, 100% shows pure DICOM
- Fix brightness adjustment to preserve overlay
- Remove debug print statements
…sidebar-label-to-QUS-analysis

17 change rf analysis sidebar label to qus analysis
…ing signal and implementing preview transition
Copilot AI review requested due to automatic review settings April 2, 2026 10:32
@OmidChaghaneh OmidChaghaneh self-assigned this Apr 2, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Integrates an analysis-loading workflow into the CEUS GUI and adds DICOM-loading support to the QUS application model, alongside broad PyQt6 .ui modernization and new generated UI modules.

Changes:

  • Added CEUS analysis loading controllers/views and wired navigation from CEUS segmentation to analysis.
  • Added QUS DICOM loader utility plus model/controller plumbing for loading DICOM pixel data.
  • Updated many Qt Designer .ui files (scoped enums, geometry, alignment flags) and added newly generated PyQt6 UI Python modules.

Reviewed changes

Copilot reviewed 72 out of 83 changed files in this pull request and generated 18 comments.

Show a summary per file
File Description
src/qus/seg_loading/ui/seg_type_selection.ui PyQt6 enum scoping/alignment updates and geometry tweaks for segmentation type selection UI.
src/qus/seg_loading/ui/seg_file_selection.ui PyQt6 enum scoping/alignment updates and geometry tweaks for segmentation file selection UI.
src/qus/seg_loading/ui/roi_preview.ui PyQt6 enum scoping/alignment updates and geometry tweaks for ROI preview UI.
src/qus/seg_loading/ui/frame_selection.ui PyQt6 enum scoping/alignment updates and geometry tweaks for frame selection UI.
src/qus/seg_loading/seg_loading_view_coordinator.py Adds controller reference bridging for ROI drawing widget (used for DICOM loading via model).
src/qus/seg_loading/seg_loading_controller.py Exposes DICOM load/get APIs via controller and injects controller into view.
src/qus/image_loading/ui/scan_type_ui.py New generated PyQt6 UI module for QUS scan type selection.
src/qus/image_loading/ui/scan_type.ui PyQt6 enum scoping/alignment updates and text tweaks (“QUS Analysis”).
src/qus/image_loading/ui/file_selection.ui PyQt6 enum scoping/alignment updates and alignment flag updates.
src/qus/image_loading/dicom_loader.py New DICOM loading/cropping/normalization helper.
src/qus/image_loading/init.py Exports DicomLoader from the image_loading package.
src/qus/export_loading/ui/export_loading_ui.py New generated PyQt6 UI module for export loading screen.
src/qus/export_loading/ui/export_loading.ui New/updated export loading .ui with scoped enums + geometry.
src/qus/config_loading/ui/custom_params.ui PyQt6 enum scoping/alignment updates and “QUS Analysis” sidebar label.
src/qus/config_loading/ui/config_type_selection.ui PyQt6 enum scoping/alignment updates and “QUS Analysis” sidebar label.
src/qus/config_loading/ui/config_preview.ui PyQt6 enum scoping/alignment + scrollbar policy updates and minor geometry changes.
src/qus/config_loading/ui/config_file_selection.ui PyQt6 enum scoping/alignment updates and “QUS Analysis” sidebar label.
src/qus/application_model.py Adds DICOM state + methods; adds debug prints for NIfTI image/seg loads.
src/qus/analysis_loading/ui/analysis_params.ui PyQt6 enum scoping/alignment updates and minor geometry changes.
src/qus/analysis_loading/ui/analysis_function_selection_ui.py New generated PyQt6 UI module for function selection screen.
src/qus/analysis_loading/ui/analysis_function_selection.ui PyQt6 enum scoping/alignment updates and “QUS Analysis” sidebar label.
src/ceus/seg_loading/views/spline.py Adds duplicate-point filtering to avoid splprep errors; strips time dimension for 3D spline.
src/ceus/seg_loading/views/draw_roi_widget.py Adds enhancement controls, pseudocolor map, confirm/review flow, and emits completed segmentation.
src/ceus/seg_loading/ui/seg_type_selection_ui.py New generated PyQt6 UI module for CEUS segmentation type selection.
src/ceus/seg_loading/seg_loading_view_coordinator.py Adds segmentation preview step and wiring from ROI/VOI drawing to preview and confirmation.
src/ceus/seg_loading/seg_loading_controller.py Connects model signals and stores confirmed manual segmentation into model.
src/ceus/seg_loading/init.py Exposes new CEUS seg preview and ROI widget components.
src/ceus/image_preprocessing/transforms.py Removes legacy CEUS preprocessing transforms module.
src/ceus/image_preprocessing/options.py Removes legacy CEUS preprocessing options module.
src/ceus/image_preprocessing/functions.py Removes legacy CEUS preprocessing functions module.
src/ceus/image_preprocessing/decorators.py Removes legacy CEUS preprocessing decorators module.
src/ceus/image_preprocessing/README.md Removes legacy CEUS preprocessing documentation.
src/ceus/image_loading/views/file_selection_widget.py Improves “FOLDER” selection detection and validation for selecting folders vs files.
src/ceus/image_loading/ui/scan_type_ui.py New generated PyQt6 UI module for CEUS scan type selection.
src/ceus/application_model.py Adds CEUS preprocessing interface, analysis worker/threading, and analysis state + signals.
src/ceus/application_controller.py Wires CEUS workflow navigation from segmentation confirmation into analysis loading.
src/ceus/analysis_loading/views/analysis_params_widget.py New CEUS analysis params widget scaffold (currently stubbed parameter UI generation).
src/ceus/analysis_loading/views/analysis_function_selection_widget.py Ports function selection widget to CEUS data objects and local MVC imports.
src/ceus/analysis_loading/views/analysis_execution_widget.py Ports execution widget to CEUS data objects and curves analysis framework.
src/ceus/analysis_loading/analysis_loading_view_coordinator.py Ports coordinator to CEUS MVC; improves error handling when no active widget.
src/ceus/analysis_loading/analysis_loading_controller.py Selects best available CEUS analysis type and aligns completion action naming.
engines/qus Updates QUS backend submodule pointer.
engines/ceus Updates CEUS backend submodule pointer.
README.md Updates clone URL and adds Windows note + explicit pyradiomics install step.
Images/functions.py Removes legacy duplicate “Images” preprocessing functions module.
Images/application_controller.py Removes legacy duplicate application controller under Images/.
Images/README.md Removes legacy duplicate README under Images/.
.gitmodules Pins submodules to main branch.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Returns:
bool: True if loaded successfully, False otherwise
"""
from src.qus.image_loading.dicom_loader import DicomLoader
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This absolute import via src.qus... is likely to fail depending on how the package is executed/installed (e.g., when src isn’t a top-level module). Prefer a package-relative import (e.g., from the local qus package) to ensure the DICOM loader can be imported reliably across entrypoints.

Suggested change
from src.qus.image_loading.dicom_loader import DicomLoader
from .image_loading.dicom_loader import DicomLoader

Copilot uses AI. Check for mistakes.
def __init__(self, image_data: UltrasoundRfImage, parent: Optional[QWidget] = None):
super().__init__(parent)
self._image_data = image_data
self.controller = None
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This introduces a public controller attribute on the view coordinator and then writes to a private attribute on the ROI widget (_parent_controller). This tightly couples view/controller internals and makes refactors brittle. Prefer passing the controller/model dependency via the ROI widget constructor (or a public setter), or use signals/callbacks to request DICOM loading without storing controller references on widgets.

Suggested change
self.controller = None
self._controller: Optional[Any] = None

Copilot uses AI. Check for mistakes.
Comment on lines 196 to +200

# Pass controller reference for DICOM loading via model
if hasattr(self, 'controller') and self.controller:
self._roi_drawing_widget._parent_controller = self.controller

Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This introduces a public controller attribute on the view coordinator and then writes to a private attribute on the ROI widget (_parent_controller). This tightly couples view/controller internals and makes refactors brittle. Prefer passing the controller/model dependency via the ROI widget constructor (or a public setter), or use signals/callbacks to request DICOM loading without storing controller references on widgets.

Suggested change
# Pass controller reference for DICOM loading via model
if hasattr(self, 'controller') and self.controller:
self._roi_drawing_widget._parent_controller = self.controller
# Optionally pass controller reference via a public API if available
if hasattr(self, "controller") and self.controller:
# Prefer a dedicated setter on the ROI widget, if it exists
set_controller = getattr(self._roi_drawing_widget, "set_controller", None)
if callable(set_controller):
set_controller(self.controller)
else:
set_parent_controller = getattr(self._roi_drawing_widget, "set_parent_controller", None)
if callable(set_parent_controller):
set_parent_controller(self.controller)

Copilot uses AI. Check for mistakes.
Comment on lines +222 to +223
# Create and setup segmentation preview widget
self._seg_preview_widget = SegPreviewWidget(self._image_data, seg_data)
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each call to show_segmentation_preview creates a new SegPreviewWidget and adds it to the stack without removing the previous preview widget first. If users redraw/reload segmentations multiple times, the stack will accumulate hidden widgets and leak memory. Before overwriting _seg_preview_widget, remove the existing widget from the stack and call deleteLater() (or reuse the existing widget by updating its data).

Copilot uses AI. Check for mistakes.
Comment on lines +232 to +234
# Add to stack and show
self.addWidget(self._seg_preview_widget)
self.setCurrentWidget(self._seg_preview_widget)
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each call to show_segmentation_preview creates a new SegPreviewWidget and adds it to the stack without removing the previous preview widget first. If users redraw/reload segmentations multiple times, the stack will accumulate hidden widgets and leak memory. Before overwriting _seg_preview_widget, remove the existing widget from the stack and call deleteLater() (or reuse the existing widget by updating its data).

Copilot uses AI. Check for mistakes.
# Crop the image
cropped_image = image[crop_top:height - crop_bottom, :]

print(f"DICOM cropped: {image.shape} -> {cropped_image.shape} (removed {crop_top} from top, {crop_bottom} from bottom)")
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This utility prints directly to stdout for error and debug reporting, which can be noisy in a GUI app and makes it hard to surface failures to the user consistently. Prefer using the application’s logging strategy (e.g., logging) and/or propagating structured errors back to the model/controller so the UI can display them via existing error signals.

Copilot uses AI. Check for mistakes.
Comment on lines +78 to +88
def _create_parameter_inputs(self) -> None:
"""Create input fields for each required parameter."""
# This implementation is simplified compared to QUS for now
# Ideally would dynamically create inputs based on CEUS requirements
pass

def _on_run_analysis_clicked(self) -> None:
"""Handle run analysis button click."""
# Collect parameters (simplified)
params = {}
self.params_configured.emit(params)
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The widget currently ignores required_params and always emits an empty params dict. If any selected analysis functions require parameters, the analysis will run with missing defaults or fail at runtime. Implement _create_parameter_inputs() to build inputs for required params and collect/validate the values in _on_run_analysis_clicked() before emitting.

Copilot uses AI. Check for mistakes.
Comment on lines +86 to +88
def __init__(self, analysis_type: str, image_data: UltrasoundImage,
config_data: Any, seg_data: CeusSeg,
selected_functions: List[str], analysis_kwargs: Dict[str, Any]):
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

config_data is accepted and stored on the worker but never passed into the analysis object. If configuration is expected for some analysis types, this will silently be ignored. Either remove config_data from the worker signature (if CEUS analyses never use it) or pass it through to the analysis constructor/API so the parameter is meaningful.

Copilot uses AI. Check for mistakes.
super().__init__()
self.analysis_type = analysis_type
self.image_data = image_data
self.config_data = config_data
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

config_data is accepted and stored on the worker but never passed into the analysis object. If configuration is expected for some analysis types, this will silently be ignored. Either remove config_data from the worker signature (if CEUS analyses never use it) or pass it through to the analysis constructor/API so the parameter is meaningful.

Copilot uses AI. Check for mistakes.
Comment on lines +110 to +115
analysis_obj = analysis_cls(
self.image_data,
self.seg_data,
self.selected_functions,
**self.analysis_kwargs
)
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

config_data is accepted and stored on the worker but never passed into the analysis object. If configuration is expected for some analysis types, this will silently be ignored. Either remove config_data from the worker signature (if CEUS analyses never use it) or pass it through to the analysis constructor/API so the parameter is meaningful.

Copilot uses AI. Check for mistakes.
@OmidChaghaneh OmidChaghaneh force-pushed the 61-feat-implement-and-integrate-analysis-loading-screen-into-ceus-workflow branch from 63e23e1 to 2d50296 Compare April 15, 2026 09:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FEAT: Implement and Integrate Analysis Loading Screen into CEUS Workflow

5 participants