Asclepios DICOM Viewer
repository·master·Indexed 42 days ago
https://github.com/gavrilovicieduard/asclepios-dicom-viewerA C++ medical imaging application using Qt and VTK for 2D and 3D visualization of DICOM datasets. It features Volume Rendering, Multiplanar Reconstruction (MPR) via the MPRMaker class, and a structured data hierarchy managed by CoreRepository, DicomReader, and the Patient, Study, Series, and Image classes. The application integrates DCMTK for DICOM file handling and network protocols.
What's inside Asclepios DICOM Viewer
- Asclepios DICOM Viewer is a medical imaging application written in C++ using the Qt framework and the Visualization Toolkit (VTK). It is designed to display DICOM images from various imaging modalities and provides both 2D and 3D visualization capabilities.
Capabilities of Asclepios DICOM Viewer
masterThe viewer supports several key medical imaging workflows:
2D Viewing
Provides an intuitive layout system for displaying 2D DICOM images obtained from different imaging modalities.
3D Post-Processing
Includes state-of-the-art post-processing techniques:
- 3D Rendering: Supports techniques such as Maximum Intensity Projection (MIP) and Volume Rendering.
- Multiplanar Reconstruction (MPR): Allows for reconstruction of multiple anatomical planes from volumetric data.
Dependencies and Libraries used by Asclepios DICOM Viewer
masterAsclepios DICOM Viewer is built upon the following libraries:
- Qt: For the user interface and application framework.
- Visualization Toolkit (VTK): For advanced 3D visualization and rendering.
- DCMTK (DICOM Toolkit): For handling DICOM file formats and network protocols.
- DICOM for VTK: For integrating DICOM data into the VTK pipeline.
- Qt-Nice-Frameless-Window: For custom window decorations in the Qt UI.
DicomReader Public API Reference
masterThe
asclepios::core::DicomReaderclass provides the following public interface for interacting with DICOM data:Method Return Type Description readFile(const std::string& t_filePath)voidLoads a DICOM file from the specified file path. getReadPatient()std::unique_ptr<Patient>Returns a unique pointer to the parsed Patientobject.getReadStudy()std::unique_ptr<Study>Returns a unique pointer to the parsed Studyobject.getReadSeries()std::unique_ptr<Series>Returns a unique pointer to the parsed Seriesobject.getReadImage()std::unique_ptr<Image>Returns a unique pointer to the parsed Imageobject.dataSetExists()boolReturns trueif the DICOM dataset was successfully loaded and is not null.Navigate image sequences in a Series
masterWhen working with single-frame images within a
Series, you can navigate the sequence using the following methods:getNextSingleFrameImage(Image* t_image): Returns the next image in the sequence after the provided image.getPreviousSingleFrameImage(Image* t_image): Returns the previous image in the sequence before the provided image.getSingleFrameImageByIndex(const int& t_index): Returns the image at a specific index.
Use the Series class to manage DICOM images
masterThe
asclepios::core::Seriesclass is a data model used to group and manage DICOM images within a specific series. It distinguishes betweensingleFrameImagesandmultiFrameImages. You can use it to retrieve metadata, navigate through image sequences, and manage the relationship between a series and its parentStudy.#include "src/core/series.h" asclepios::core::Series series; // Set basic DICOM metadata series.setUID("1.2.3.4.5.6"); series.setDescription("Axial T2"); series.setDate("20230101"); // Add images to the series bool isNew = false; auto imagePtr = series.addSingleFrameImage(std::move(myUniqueImage), isNew); // Access images auto images = series.getSinlgeFrameImages(); // Navigate sequence Image* nextImage = series.getNextSingleFrameImage(currentImage);Configure volume rendering transfer functions with TransferFunction
masterThe
asclepios::gui::TransferFunctionclass manages the visual properties of volume rendering, including window/level settings, lighting (shading), and the mapping of intensity values to colors and opacity.Lighting and Window/Level
You can control the appearance of the rendered volume using:
- Window/Level: Controls the intensity range displayed.
- Shading: Toggles shading on/off via
setHasShadeand configures lighting parameters likesetAmbient,setDiffuse,setSpecular, andsetSpecularPower.
Color and Opacity Mapping
The class manages two types of transfer functions:
- Color Transfer Function: Maps intensity values to RGB colors. It uses
vtkColorTransferFunctioninternally. - Opacity Transfer Function: Maps intensity values to alpha (transparency) values. It uses
vtkPiecewiseFunctioninternally.
Data Loading
- File Loading: Use
loadFilterFromFile(const QString& t_fileName)to load transfer function configurations from a file. - JSON Integration: The class provides internal methods
extractColorFunctionInfoandextractOpacityFunctionInfoto populate transfer functions fromQJsonArraydata structures.
#include "src/gui/transferfunction.h" asclepios::gui::TransferFunction tf; // Configure window/level tf.setWindow(400); tf.setLevel(40); // Configure shading/lighting tf.setHasShade(true); tf.setAmbient(0.2); tf.setSpecular(0.8); // Access underlying VTK functions for advanced manipulation auto* colorFunc = tf.getColorFunction(); auto* opacityFunc = tf.getOpacityFunction();Manage 2D and 3D view tabs with TabWidget
masterThe
TabWidgetclass is a UI component used to manage different types of DICOM view tabs (2D and 3D/MPR). It acts as a container forWidgetBaseobjects and provides methods to create, reset, and manipulate these view tabs.Creating View Tabs
- Use
createWidget2D()to instantiate a 2D viewer tab. - Use
createWidgetMPR3D(WidgetBase::WidgetType t_type)to instantiate a 3D/Multiplanar Reconstruction tab. The type of 3D widget is determined by theWidgetBase::WidgetTypeprovided. - Use
resetWidget()to clear the current tab content.
Tab Manipulation
setTabTitle(int t_index, const QString& t_name): Sets the display name for a specific tab index.closeWidget(int t_index): Closes the tab at the specified index.onMaximize(): A slot to trigger the maximization of the current tab view.
State Inspection
getWidgetType(): Returns the currentWidgetBase::WidgetTypeof the active tab.getTabbedWidget(): Returns the pointer to the underlyingWidgetBaseinstance.getActiveTabbedWidget(): Returns theWidgetBasecurrently being viewed.getIsActive(): Returns whether the tab widget is currently active.getIsMaximized(): Returns whether the tab view is in maximized mode.
// Example conceptual usage of TabWidget methods asclepios::gui::TabWidget* tabWidget = new asclepios::gui::TabWidget(parent); // Create a 2D view tabWidget->createWidget2D(); // Create a specific 3D MPR view tabWidget->createWidgetMPR3D(WidgetBase::WidgetType::MPR); // Set a custom title for the first tab tabWidget->setTabTitle(0, "Axial View"); // Check current state if (tabWidget->getIsMaximized()) { // handle maximized state }- Use
Control MPR view state and generation
masterOnce
MPRMakeris configured, use the following methods to manage the reconstruction and view state:createMPR(): Triggers the generation of the Multiplanar Reconstruction views.create3DMatrix(): Generates the necessary 3D transformation matrices.resetMatrixesToInitialPosition(): Resets the transformation matrices to their default orientation.resetWindowLevel(): Resets the window and level settings to the values provided viasetInitialWindowandsetInitialLevel.
Use the StudyList UI component
masterThe
asclepios::gui::StudyListclass is aQListWidgetbased component used to display and manage a list of DICOM studies and series. It allows developers to associate a specificcore::Patientandcore::Studywith the list view and provides methods to populate the list with series and image data.Key Functionalities:
- Data Association: Link the list to a specific patient or study using
setPatient()andsetStudy(). - Populating Content: Use
insertNewSeries()to add new series and image information to the list. - Concurrency Tracking: Access active background tasks via
getFutures()to monitor loading or processing states. - Signals: The
finishConcurrent()signal is emitted when concurrent operations associated with the list have completed.
// Example usage of StudyList #include "src/gui/studylist.h" asclepios::gui::StudyList* studyList = new asclepios::gui::StudyList(parent); // Associate with data studyList->setPatient(myPatientPointer); studyList->setStudy(myStudyPointer); // Add content studyList->insertNewSeries(mySeriesPointer, myImagePointer); // Monitor background tasks std::vector<QFuture<void>> tasks = studyList->getFutures(); // Connect to completion signal connect(studyList, &asclepios::gui::StudyList::finishConcurrent, []() { // Handle completion });- Data Association: Link the list to a specific patient or study using
Add thumbnails to the ThumbnailsWidget
masterThe
ThumbnailsWidgetclass provides a slotaddThumbnailto populate the UI with DICOM image thumbnails. To add an entry, you must provide pointers to the correspondingcore::Patient,core::Study,core::Series, andcore::Imageobjects. This method handles the hierarchical organization of the thumbnails within the widget.// Assuming you have pointers to the core DICOM objects asclepios::gui::ThumbnailsWidget* thumbnailsWidget = ...; thumbnailsWidget->addThumbnail( patient_ptr, study_ptr, series_ptr, image_ptr );Manage application data with CoreRepository
masterThe
CoreRepositoryclass serves as the central repository for managing the hierarchy of DICOM data within the application. It manages the lifecycle and ownership ofPatient,Study,Series, andImageobjects.Data Hierarchy and Ownership
- Ownership: The repository owns the
Patientobjects viastd::unique_ptr. Other entities likeStudy,Series, andImageare managed via raw pointers (Patient*,Study*, etc.) which are updated as the user navigates the DICOM hierarchy. - Navigation State: The repository tracks the 'last' accessed entity at each level of the hierarchy (
getLastPatient(),getLastStudy(),getLastSeries(), andgetLastImage()). - Change Tracking: You can check if new data has been added to the current context using
newSeriesAdded()andnewImageAdded().
#include "src/core/corerepository.h" asclepios::core::CoreRepository repo; // Adding data repo.addPatient(std::make_unique<Patient>(...)); // Accessing current state asclepios::core::Patient* currentPatient = repo.getLastPatient(); if (repo.newSeriesAdded()) { // Handle new series logic } // Deleting data repo.deletePatient(currentPatient); // or repo.deleteAllPatients();- Ownership: The repository owns the