├── src ├── CMakeLists.txt ├── PROJECT.cxx ├── FixedPointVolumeRayCastMapperCT.h ├── readDICOMSeries.h ├── itkWaterShedCode.h ├── vtkVolumeRenderer.h └── ConfidenceConnected3D.h ├── requirements.txt ├── CLAUDE.md └── README.md /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(MedicalDataVisualization3D) 3 | 4 | # Set C++ standard 5 | set(CMAKE_CXX_STANDARD 11) 6 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 7 | 8 | # Find packages 9 | find_package(VTK REQUIRED) 10 | find_package(ITK REQUIRED) 11 | 12 | # Include directories 13 | include(${VTK_USE_FILE}) 14 | include(${ITK_USE_FILE}) 15 | 16 | # Handle ITK-VTK glue 17 | if(ITKVtkGlue_LOADED) 18 | find_package(VTK REQUIRED) 19 | include(${VTK_USE_FILE}) 20 | else() 21 | find_package(ItkVtkGlue REQUIRED) 22 | include(${ItkVtkGlue_USE_FILE}) 23 | set(Glue ItkVtkGlue) 24 | endif() 25 | 26 | # Add executable 27 | add_executable(MedicalDataVisualization3D PROJECT.cxx) 28 | 29 | # Set target properties 30 | set_target_properties(MedicalDataVisualization3D PROPERTIES 31 | OUTPUT_NAME "PROJECT" 32 | MACOSX_BUNDLE TRUE 33 | ) 34 | 35 | # Link libraries 36 | target_link_libraries(MedicalDataVisualization3D 37 | ${Glue} 38 | ${ITK_LIBRARIES} 39 | ${VTK_LIBRARIES} 40 | ) 41 | 42 | # Platform-specific configurations 43 | if(WIN32) 44 | set_target_properties(MedicalDataVisualization3D PROPERTIES 45 | WIN32_EXECUTABLE TRUE 46 | ) 47 | endif() 48 | 49 | # Install target 50 | install(TARGETS MedicalDataVisualization3D 51 | RUNTIME DESTINATION bin 52 | BUNDLE DESTINATION . 53 | ) 54 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Medical Data Visualization 3D - System Requirements 2 | 3 | ## Core Dependencies 4 | 5 | ### Build System 6 | - CMake >= 3.10 7 | - C++11 compatible compiler 8 | 9 | ### Medical Image Processing Libraries 10 | - ITK (Insight Segmentation and Registration Toolkit) >= 5.0 11 | - Installation guide: https://www.youtube.com/watch?v=vZOMu5YSfoI 12 | - Official docs: https://itk.org/ITK/resources/software.html 13 | 14 | - VTK (Visualization Toolkit) >= 9.0 15 | - Installation guide: https://www.youtube.com/watch?v=IgvbhyDh8r0 16 | - Official docs: https://vtk.org/download/ 17 | 18 | ### Graphics Libraries 19 | - OpenGL >= 3.0 (for GPU-accelerated volume rendering) 20 | - GPU drivers supporting OpenGL/CUDA (recommended for performance) 21 | 22 | ## Platform-Specific Requirements 23 | 24 | ### Windows 25 | - Visual Studio >= 2015 (2019 or later recommended) 26 | - Windows SDK 27 | - **Important**: Run Visual Studio as Administrator during build 28 | 29 | ### Linux (Ubuntu/Debian) 30 | - GCC >= 7.0 or Clang >= 6.0 31 | - Development packages: 32 | ```bash 33 | sudo apt-get install build-essential cmake 34 | sudo apt-get install libvtk9-dev libinsighttoolkit5-dev 35 | sudo apt-get install libgl1-mesa-dev libglu1-mesa-dev 36 | ``` 37 | 38 | ### macOS 39 | - Xcode Command Line Tools 40 | - Homebrew (recommended for dependency management) 41 | ```bash 42 | brew install cmake vtk itk 43 | ``` 44 | 45 | ## Optional Dependencies 46 | - CUDA Toolkit (for GPU-accelerated processing) 47 | - Additional ITK modules for extended file format support 48 | 49 | ## Hardware Requirements 50 | - Minimum 4GB RAM (8GB+ recommended for large medical datasets) 51 | - Graphics card with OpenGL 3.0+ support 52 | - Sufficient disk space for medical image datasets 53 | 54 | ## Known Limitations 55 | - Current codebase includes Windows-specific dependencies (windows.h, dos.h) 56 | - Cross-platform compatibility may require source code modifications 57 | - DICOM viewing optimized for Windows environment -------------------------------------------------------------------------------- /src/PROJECT.cxx: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #ifdef _WIN32 8 | #include 9 | #include 10 | #elif __linux__ 11 | #include 12 | #elif __APPLE__ 13 | #include 14 | #endif 15 | 16 | #include "vtkVolumeRenderer.h" 17 | 18 | #include "FixedPointVolumeRayCastMapperCT.h" 19 | 20 | #include "ConfidenceConnected3D.h" 21 | 22 | #include "readDICOMSeries.h" 23 | 24 | #include "itkWaterShedCode.h" 25 | 26 | 27 | std::string s; 28 | 29 | void delay(const std::string& str) 30 | { 31 | for(size_t i = 0; i < str.size(); i++) 32 | { 33 | std::cout << str[i]; 34 | } 35 | std::cout << std::endl; 36 | } 37 | 38 | 39 | int main() 40 | { 41 | while(true) 42 | { 43 | std::cout << "\nSelect operation code:" << std::endl; 44 | std::cout << "Code 1: Volume Rendering for Brain Data" << std::endl; 45 | std::cout << "Code 2: Volume Rendering for CT Bone Data" << std::endl; 46 | std::cout << "Code 3: Medical Data Watershed Segmentation" << std::endl; 47 | std::cout << "Code 4: DICOM file Series Viewer" << std::endl; 48 | std::cout << "Code 5: Confidence Connected Segmentation of Brain White Matter" << std::endl; 49 | std::cout << "Type E/e to Exit" << std::endl; 50 | char c; 51 | std::cout << ">> "; 52 | std::cin >> c; 53 | if (c == 'E' || c == 'e') 54 | return EXIT_SUCCESS; 55 | 56 | std::string dir, type; 57 | std::cin.ignore(); // Clear input buffer 58 | switch(c) 59 | { 60 | case '1': 61 | s = "Volume Rendering for Brain Data"; 62 | delay(s); 63 | std::cout << "Enter directory/filepath file_type[ '-FILE / -DIR' ]: "; 64 | std::cin >> dir >> type; 65 | renderBrain(const_cast(dir.c_str()), const_cast(type.c_str())); 66 | break; 67 | case '2': 68 | s = "Volume Rendering for CT Bone Data"; 69 | delay(s); 70 | renderBone(); 71 | break; 72 | case '3': 73 | s = "Medical Data Watershed Segmentation"; 74 | delay(s); 75 | std::cout << "Enter file path: "; 76 | std::string file_name; 77 | std::cin >> file_name; 78 | watershedSegmentation(const_cast(file_name.c_str())); 79 | break; 80 | case '4': 81 | s = "DICOM file Series Viewer"; 82 | delay(s); 83 | std::cout << "Enter directory path: "; 84 | std::cin >> dir; 85 | showSeries(const_cast(dir.c_str())); 86 | break; 87 | case '5': 88 | s = "Confidence Connected Segmentation of Brain White Matter"; 89 | delay(s); 90 | confidenceSeg(); 91 | break; 92 | } 93 | } 94 | return EXIT_SUCCESS; 95 | } 96 | -------------------------------------------------------------------------------- /CLAUDE.md: -------------------------------------------------------------------------------- 1 | # CLAUDE.md 2 | 3 | This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. 4 | 5 | ## Project Overview 6 | 7 | Medical-Data-Visualization-3D is a C++ medical imaging application that provides 3D visualization and analysis of medical data including DICOM, MRI, and CT scans. The application uses ITK (Insight Segmentation and Registration Toolkit) and VTK (Visualization Toolkit) libraries to process and render medical images. 8 | 9 | ## Build and Development Commands 10 | 11 | ### Building the Project 12 | ```bash 13 | mkdir build && cd build 14 | cmake ../src 15 | # On Windows: Open the generated .sln file in Visual Studio and build 16 | # On Linux/Mac: make 17 | ``` 18 | 19 | ### Prerequisites 20 | - Visual Studio >= 2015 (Windows) 21 | - CMake 22 | - VTK library (https://www.youtube.com/watch?v=IgvbhyDh8r0) 23 | - ITK library (https://www.youtube.com/watch?v=vZOMu5YSfoI) 24 | - Run as Administrator (Windows) 25 | 26 | ### Executable Location 27 | After building, the executable is located in `/bin/debug/` folder. 28 | 29 | ## Architecture Overview 30 | 31 | ### Core Application Structure 32 | - **PROJECT.cxx**: Main entry point with console menu system offering 5 medical visualization operations 33 | - **Header-only modules**: All functionality is implemented in header files (.h) that contain both declarations and implementations 34 | 35 | ### Key Functional Modules 36 | 37 | 1. **Volume Rendering** (`vtkVolumeRenderer.h`) 38 | - Brain data volume rendering with GPU ray casting 39 | - Supports both DICOM directories (-DIR) and MetaImage files (-FILE) 40 | - Complex color transfer functions for anatomical visualization 41 | - Uses vtkGPUVolumeRayCastMapper for performance 42 | 43 | 2. **DICOM Series Viewer** (`readDICOMSeries.h`) 44 | - Interactive slice-by-slice viewing of DICOM series 45 | - Custom vtkInteractorStyleImage with keyboard/mouse wheel navigation 46 | - Real-time slice number display and usage instructions 47 | 48 | 3. **Medical Segmentation** (`ConfidenceConnected3D.h`) 49 | - ITK-based confidence connected segmentation for brain white matter 50 | - ITK-to-VTK pipeline conversion for visualization 51 | - Predefined seed points for brain segmentation 52 | - Combines image processing (ITK) with 3D rendering (VTK) 53 | 54 | 4. **CT Bone Rendering** (`FixedPointVolumeRayCastMapperCT.h`) 55 | - Specialized volume rendering for CT bone data 56 | - Fixed-point ray casting for bone visualization 57 | 58 | 5. **Watershed Segmentation** (`itkWaterShedCode.h`) 59 | - ITK watershed algorithm implementation 60 | - Advanced image segmentation capabilities 61 | 62 | ### Technology Stack 63 | - **C++**: Core implementation language 64 | - **ITK**: Medical image processing and analysis 65 | - **VTK**: 3D visualization and rendering 66 | - **CMake**: Cross-platform build system 67 | - **Windows-specific**: Uses windows.h, dos.h for system operations 68 | 69 | ### Data Flow Pattern 70 | The application follows a consistent pattern: 71 | 1. User selects operation from console menu 72 | 2. Input file/directory path specification 73 | 3. ITK processing (for segmentation) or direct VTK loading 74 | 4. VTK pipeline setup with volume properties and transfer functions 75 | 5. Interactive 3D rendering window with trackball camera controls 76 | 77 | ### Key Implementation Notes 78 | - All visualization uses GPU-accelerated volume ray casting when available 79 | - Complex predefined color transfer functions for anatomical accuracy 80 | - ITK-VTK pipeline integration using specialized connector templates 81 | - Custom interactor styles for medical image navigation 82 | - Platform-specific code includes Windows dependencies 83 | 84 | ### File Structure Conventions 85 | - Main executable: PROJECT.cxx 86 | - Functional modules: Descriptive header names ending in .h 87 | - Build configuration: CMakeLists.txt in src/ directory 88 | - All implementation in headers (no separate .cpp files for modules) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Medical Data Visualization 3D 2 | 3 | A comprehensive medical imaging application for 3D visualization and analysis of medical data including DICOM, MRI, and CT scans. Built with ITK and VTK libraries for professional-grade medical image processing and rendering. 4 | 5 | ## Features 6 | 7 | - **Volume Rendering**: High-performance 3D visualization of brain and CT bone data using GPU ray casting 8 | - **DICOM Series Viewer**: Interactive slice-by-slice navigation through medical image series 9 | - **Medical Segmentation**: 10 | - Confidence Connected segmentation for brain white matter extraction 11 | - Watershed segmentation for advanced image analysis 12 | - **Multi-format Support**: DICOM directories, MetaImage files (.mha), MRI, and CT data 13 | - **Interactive Navigation**: Mouse wheel and keyboard controls for 3D manipulation 14 | - **Real-time Rendering**: GPU-accelerated volume rendering with customizable transfer functions 15 | 16 | ## Installation 17 | 18 | ### Prerequisites 19 | 20 | #### Windows 21 | - **Visual Studio** 2015 or later 22 | - **CMake** 3.0+ 23 | - **VTK** (Visualization Toolkit) - [Installation Guide](https://www.youtube.com/watch?v=IgvbhyDh8r0) 24 | - **ITK** (Insight Segmentation and Registration Toolkit) - [Installation Guide](https://www.youtube.com/watch?v=vZOMu5YSfoI) 25 | 26 | #### Linux/Ubuntu 27 | - **GCC** 7.0+ or **Clang** 6.0+ 28 | - **CMake** 3.0+ 29 | - **VTK** development libraries 30 | - **ITK** development libraries 31 | - **OpenGL** development libraries 32 | 33 | ```bash 34 | # Ubuntu/Debian 35 | sudo apt-get update 36 | sudo apt-get install build-essential cmake 37 | sudo apt-get install libvtk9-dev libinsighttoolkit5-dev 38 | sudo apt-get install libgl1-mesa-dev libglu1-mesa-dev 39 | ``` 40 | 41 | #### macOS 42 | - **Xcode** Command Line Tools 43 | - **CMake** 3.0+ 44 | - **VTK** and **ITK** (via Homebrew recommended) 45 | 46 | ```bash 47 | # Install Homebrew if not already installed 48 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 49 | 50 | # Install dependencies 51 | brew install cmake vtk itk 52 | ``` 53 | 54 | ### Building the Project 55 | 56 | 1. **Clone the repository** 57 | ```bash 58 | git clone 59 | cd Medical-Data-Visualization-3D 60 | ``` 61 | 62 | 2. **Build with CMake** 63 | ```bash 64 | mkdir build 65 | cd build 66 | cmake ../src 67 | ``` 68 | 69 | 3. **Compile** 70 | 71 | #### Windows 72 | - Open the generated `.sln` solution file in Visual Studio 73 | - **Run Visual Studio as Administrator** 74 | - Build the solution 75 | - Executable will be generated in `/bin/debug/` 76 | 77 | #### Linux/macOS 78 | ```bash 79 | make -j$(nproc) # Linux 80 | make -j$(sysctl -n hw.ncpu) # macOS 81 | ``` 82 | 83 | 4. **Run the application** 84 | ```bash 85 | # Windows 86 | ./bin/debug/PROJECT.exe 87 | 88 | # Linux/macOS 89 | ./PROJECT 90 | ``` 91 | 92 | ## Usage 93 | 94 | The application provides a console-based menu with 5 main operations: 95 | 96 | 1. **Volume Rendering for Brain Data**: Render 3D brain volumes from DICOM or MetaImage files 97 | 2. **Volume Rendering for CT Bone Data**: Specialized CT bone visualization 98 | 3. **Medical Data Watershed Segmentation**: Advanced image segmentation using watershed algorithm 99 | 4. **DICOM Series Viewer**: Navigate through DICOM image series slice by slice 100 | 5. **Confidence Connected Segmentation**: Extract brain white matter regions 101 | 102 | ### Controls 103 | - **Mouse Wheel**: Navigate through image slices 104 | - **Arrow Keys**: Up/Down for slice navigation 105 | - **Right Mouse + Drag**: Zoom and rotate in 3D view 106 | - **Trackball Camera**: Interactive 3D navigation 107 | 108 | ## Architecture 109 | 110 | - **Language**: C++ 111 | - **Medical Image Processing**: ITK (Insight Toolkit) 112 | - **3D Visualization**: VTK (Visualization Toolkit) 113 | - **Build System**: CMake 114 | - **Platform**: Cross-platform (Windows, Linux, macOS) 115 | 116 | The application uses a modular header-only design with specialized modules for different medical imaging tasks, featuring ITK-to-VTK pipeline integration for seamless data processing and visualization. 117 | 118 | ## Screenshots 119 | 120 | ![Volume Rendering](https://user-images.githubusercontent.com/36689470/66020013-832ff200-e507-11e9-8f65-e1b60032b28c.png) 121 | ![DICOM Viewer](https://user-images.githubusercontent.com/36689470/66020054-9e026680-e507-11e9-87c5-563f4fad9bed.png) 122 | ![Segmentation](https://user-images.githubusercontent.com/36689470/66020132-defa7b00-e507-11e9-9af2-ac55ea4dc90f.png) 123 | ![3D Rendering](https://user-images.githubusercontent.com/36689470/66020154-f46fa500-e507-11e9-811c-865212b95a84.png) 124 | 125 | ## Contributing 126 | 127 | This project is part of a medical imaging research initiative. Contributions are welcome for: 128 | - Additional medical image format support 129 | - Performance optimizations 130 | - UI/UX enhancements 131 | - Documentation improvements 132 | 133 | ## Known Limitations 134 | 135 | ⚠️ **Note**: The current codebase includes Windows-specific dependencies (`windows.h`, `dos.h`) that may require modification for full Linux/macOS compatibility. The build instructions above assume these dependencies can be conditionally compiled or replaced with cross-platform alternatives. 136 | 137 | ## License 138 | 139 | Please refer to the project's license file for usage rights and restrictions. 140 | -------------------------------------------------------------------------------- /src/FixedPointVolumeRayCastMapperCT.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #define MHA_FILETYPE 2 23 | 24 | namespace 25 | { 26 | void PrintUsage() 27 | { 28 | cout << "Usage: " << endl; 29 | cout << endl; 30 | cout << " FixedPointVolumeRayCastMapper for Bone CT Visualization " << endl; 31 | cout << endl; 32 | cout << "where options may include: " << endl; 33 | cout << endl; 34 | cout << " -DICOM " << endl; 35 | cout << " -MHA " << endl; 36 | cout << " -CT_Bone" << endl; 37 | cout << "You must use either the -DICOM option to specify the directory where" << endl; 38 | cout << "the data is located or the -MHA option to specify the path of a .mha/.mhd file." << endl; 39 | cout << endl; 40 | cout << "Example: -DICOM Head" << endl; 41 | cout << endl; 42 | } 43 | } 44 | void renderBone() 45 | { 46 | 47 | PrintUsage(); 48 | 49 | int count = 1; 50 | char *dirname = NULL; 51 | double opacityWindow = 4096; 52 | double opacityLevel = 2048; 53 | int blendType = 4; 54 | int clip = 0; 55 | double reductionFactor = 1.0; 56 | double frameRate = 10.0; 57 | char *fileName=0; 58 | int fileType=0; 59 | 60 | bool independentComponents=true; 61 | 62 | cout << "File/Directory? '-MHA / -DICOM': "; 63 | char choice[100]; 64 | cin >> choice; 65 | cout << "Enter path: "; 66 | char path[1000]; 67 | cin >> path; 68 | if (!strcmp(choice, "-DICOM")) 69 | { 70 | size_t size = strlen(path) + 1; 71 | dirname = new char[size]; 72 | snprintf(dirname, size, "%s", path); 73 | count += 2; 74 | } 75 | else if (!strcmp(choice, "-MHA")) 76 | { 77 | size_t size = strlen(path) + 1; 78 | fileName = new char[size]; 79 | fileType = MHA_FILETYPE; 80 | snprintf(fileName, size, "%s", path); 81 | count += 2; 82 | } 83 | else 84 | { 85 | cout << "Unrecognized option: " << choice << endl; 86 | cout << endl; 87 | PrintUsage(); 88 | return; 89 | } 90 | 91 | if ( !dirname && !fileName) 92 | { 93 | cout << "Error: you must specify a directory of DICOM data or a .mha!" << endl; 94 | cout << endl; 95 | PrintUsage(); 96 | return; 97 | } 98 | 99 | vtkNamedColors *colors = vtkNamedColors::New(); 100 | vtkRenderer *renderer = vtkRenderer::New(); 101 | vtkRenderWindow *renWin = vtkRenderWindow::New(); 102 | renWin->AddRenderer(renderer); 103 | 104 | 105 | vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); 106 | iren->SetRenderWindow(renWin); 107 | iren->SetDesiredUpdateRate(frameRate / (1+clip) ); 108 | 109 | iren->GetInteractorStyle()->SetDefaultRenderer(renderer); 110 | 111 | vtkAlgorithm *reader=0; 112 | vtkImageData *input=0; 113 | if(dirname) 114 | { 115 | vtkDICOMImageReader *dicomReader = vtkDICOMImageReader::New(); 116 | dicomReader->SetDirectoryName(dirname); 117 | dicomReader->Update(); 118 | input=dicomReader->GetOutput(); 119 | reader=dicomReader; 120 | } 121 | else if ( fileType == MHA_FILETYPE ) 122 | { 123 | vtkMetaImageReader *metaReader = vtkMetaImageReader::New(); 124 | metaReader->SetFileName(fileName); 125 | metaReader->Update(); 126 | input=metaReader->GetOutput(); 127 | reader=metaReader; 128 | } 129 | else 130 | { 131 | cout << "Error! Not MHA!" << endl; 132 | return; 133 | } 134 | 135 | int dim[3]; 136 | input->GetDimensions(dim); 137 | if ( dim[0] < 2 || dim[1] < 2 || dim[2] < 2 ) 138 | { 139 | cout << "Error loading data!" << endl; 140 | return; 141 | } 142 | 143 | vtkVolume *volume = vtkVolume::New(); 144 | vtkFixedPointVolumeRayCastMapper *mapper = vtkFixedPointVolumeRayCastMapper::New(); 145 | 146 | mapper->SetInputConnection( reader->GetOutputPort() ); 147 | 148 | vtkColorTransferFunction *colorFun = vtkColorTransferFunction::New(); 149 | vtkPiecewiseFunction *opacityFun = vtkPiecewiseFunction::New(); 150 | 151 | vtkVolumeProperty *property = vtkVolumeProperty::New(); 152 | property->SetIndependentComponents(independentComponents); 153 | property->SetColor( colorFun ); 154 | property->SetScalarOpacity( opacityFun ); 155 | property->SetInterpolationTypeToLinear(); 156 | 157 | volume->SetProperty( property ); 158 | volume->SetMapper( mapper ); 159 | 160 | colorFun->AddRGBPoint(-3024, 0, 0, 0, 0.5, 0.0); 161 | colorFun->AddRGBPoint(-16, 0.73, 0.25, 0.30, 0.49, .61); 162 | colorFun->AddRGBPoint(641, .90, .82, .56, .5, 0.0); 163 | colorFun->AddRGBPoint(3071, 1, 1, 1, .5, 0.0); 164 | 165 | opacityFun->AddPoint(-3024, 0, 0.5, 0.0); 166 | opacityFun->AddPoint(-16, 0, .49, .61); 167 | opacityFun->AddPoint(641, .72, .5, 0.0); 168 | opacityFun->AddPoint(3071, .71, 0.5, 0.0); 169 | 170 | mapper->SetBlendModeToComposite(); 171 | property->ShadeOn(); 172 | property->SetAmbient(0.1); 173 | property->SetDiffuse(0.9); 174 | property->SetSpecular(0.2); 175 | property->SetSpecularPower(10.0); 176 | property->SetScalarOpacityUnitDistance(0.8919); 177 | 178 | renWin->SetSize(600,600); 179 | renWin->Render(); 180 | 181 | renderer->AddVolume( volume ); 182 | 183 | renderer->ResetCamera(); 184 | renderer->SetBackground(colors->GetColor3d("SlateGray").GetData()); 185 | 186 | renWin->Render(); 187 | 188 | iren->Start(); 189 | 190 | opacityFun->Delete(); 191 | colorFun->Delete(); 192 | property->Delete(); 193 | 194 | volume->Delete(); 195 | mapper->Delete(); 196 | reader->Delete(); 197 | renderer->Delete(); 198 | renWin->Delete(); 199 | iren->Delete(); 200 | 201 | return; 202 | } 203 | -------------------------------------------------------------------------------- /src/readDICOMSeries.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | using namespace std; 18 | 19 | class StatusMessage 20 | { 21 | public: 22 | static string Format(int slice, int maxSlice) 23 | { 24 | stringstream tmp; 25 | tmp << "Slice Number " << slice + 1 << "/" << maxSlice + 1; 26 | return tmp.str(); 27 | } 28 | }; 29 | 30 | 31 | class myVtkInteractorStyleImage : public vtkInteractorStyleImage 32 | { 33 | public: 34 | static myVtkInteractorStyleImage* New(); 35 | vtkTypeMacro(myVtkInteractorStyleImage, vtkInteractorStyleImage); 36 | 37 | protected: 38 | vtkImageViewer2* _ImageViewer; 39 | vtkTextMapper* _StatusMapper; 40 | int _Slice; 41 | int _MinSlice; 42 | int _MaxSlice; 43 | 44 | public: 45 | void SetImageViewer(vtkImageViewer2* imageViewer) 46 | { 47 | _ImageViewer = imageViewer; 48 | _MinSlice = imageViewer->GetSliceMin(); 49 | _MaxSlice = imageViewer->GetSliceMax(); 50 | _Slice = _MinSlice; 51 | //cout << "Slicer: Min = " << _MinSlice << ", Max = " << _MaxSlice << std::endl; 52 | } 53 | 54 | void SetStatusMapper(vtkTextMapper* statusMapper) 55 | { 56 | _StatusMapper = statusMapper; 57 | } 58 | 59 | 60 | protected: 61 | void MoveSliceForward() 62 | { 63 | if(_Slice < _MaxSlice) 64 | { 65 | _Slice += 1; 66 | //cout << "MoveSliceForward::Slice = " << _Slice << std::endl; 67 | _ImageViewer->SetSlice(_Slice); 68 | string msg = StatusMessage::Format(_Slice, _MaxSlice); 69 | _StatusMapper->SetInput(msg.c_str()); 70 | _ImageViewer->Render(); 71 | } 72 | } 73 | 74 | void MoveSliceBackward() 75 | { 76 | if(_Slice > _MinSlice) 77 | { 78 | _Slice -= 1; 79 | //cout << "MoveSliceBackward::Slice = " << _Slice << std::endl; 80 | _ImageViewer->SetSlice(_Slice); 81 | std::string msg = StatusMessage::Format(_Slice, _MaxSlice); 82 | _StatusMapper->SetInput(msg.c_str()); 83 | _ImageViewer->Render(); 84 | } 85 | } 86 | 87 | 88 | virtual void OnKeyDown() 89 | { 90 | std::string key = this->GetInteractor()->GetKeySym(); 91 | if(key.compare("Up") == 0) 92 | { 93 | //cout << "Up arrow key was pressed." << endl; 94 | MoveSliceForward(); 95 | } 96 | else if(key.compare("Down") == 0) 97 | { 98 | //cout << "Down arrow key was pressed." << endl; 99 | MoveSliceBackward(); 100 | } 101 | // forward event 102 | vtkInteractorStyleImage::OnKeyDown(); 103 | } 104 | 105 | 106 | virtual void OnMouseWheelForward() 107 | { 108 | //std::cout << "Scrolled mouse wheel forward." << std::endl; 109 | MoveSliceForward(); 110 | 111 | } 112 | 113 | 114 | virtual void OnMouseWheelBackward() 115 | { 116 | //std::cout << "Scrolled mouse wheel backward." << std::endl; 117 | if(_Slice > _MinSlice) 118 | { 119 | MoveSliceBackward(); 120 | } 121 | 122 | } 123 | }; 124 | 125 | vtkStandardNewMacro(myVtkInteractorStyleImage); 126 | 127 | 128 | void showSeries(char *dir) 129 | { 130 | 131 | string folder = dir; 132 | 133 | vtkSmartPointer reader = vtkSmartPointer::New(); 134 | reader->SetDirectoryName(folder.c_str()); 135 | reader->Update(); 136 | 137 | vtkSmartPointer imageViewer = vtkSmartPointer::New(); 138 | imageViewer->SetInputConnection(reader->GetOutputPort()); 139 | 140 | vtkSmartPointer sliceTextProp = vtkSmartPointer::New(); 141 | sliceTextProp->SetFontFamilyToCourier(); 142 | sliceTextProp->SetFontSize(20); 143 | sliceTextProp->SetVerticalJustificationToBottom(); 144 | sliceTextProp->SetJustificationToLeft(); 145 | 146 | vtkSmartPointer sliceTextMapper = vtkSmartPointer::New(); 147 | string msg = StatusMessage::Format(imageViewer->GetSliceMin(), imageViewer->GetSliceMax()); 148 | sliceTextMapper->SetInput(msg.c_str()); 149 | sliceTextMapper->SetTextProperty(sliceTextProp); 150 | 151 | vtkSmartPointer sliceTextActor = vtkSmartPointer::New(); 152 | sliceTextActor->SetMapper(sliceTextMapper); 153 | sliceTextActor->SetPosition(15, 10); 154 | 155 | vtkSmartPointer usageTextProp = vtkSmartPointer::New(); 156 | usageTextProp->SetFontFamilyToCourier(); 157 | usageTextProp->SetFontSize(14); 158 | usageTextProp->SetVerticalJustificationToTop(); 159 | usageTextProp->SetJustificationToLeft(); 160 | 161 | vtkSmartPointer usageTextMapper = vtkSmartPointer::New(); 162 | usageTextMapper->SetInput("- Slice with mouse wheel\n or Up/Down-Key\n- Zoom with pressed right\n mouse button while dragging"); 163 | usageTextMapper->SetTextProperty(usageTextProp); 164 | 165 | vtkSmartPointer usageTextActor = vtkSmartPointer::New(); 166 | usageTextActor->SetMapper(usageTextMapper); 167 | usageTextActor->GetPositionCoordinate()->SetCoordinateSystemToNormalizedDisplay(); 168 | usageTextActor->GetPositionCoordinate()->SetValue( 0.05, 0.95); 169 | 170 | vtkSmartPointer renderWindowInteractor = vtkSmartPointer::New(); 171 | 172 | vtkSmartPointer myInteractorStyle = vtkSmartPointer::New(); 173 | 174 | 175 | myInteractorStyle->SetImageViewer(imageViewer); 176 | myInteractorStyle->SetStatusMapper(sliceTextMapper); 177 | 178 | imageViewer->SetupInteractor(renderWindowInteractor); 179 | 180 | renderWindowInteractor->SetInteractorStyle(myInteractorStyle); 181 | 182 | imageViewer->GetRenderer()->AddActor2D(sliceTextActor); 183 | imageViewer->GetRenderer()->AddActor2D(usageTextActor); 184 | 185 | 186 | imageViewer->Render(); 187 | imageViewer->GetRenderer()->ResetCamera(); 188 | imageViewer->Render(); 189 | renderWindowInteractor->Start(); 190 | return; 191 | } 192 | -------------------------------------------------------------------------------- /src/itkWaterShedCode.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #ifdef _WIN32 7 | #include 8 | #include 9 | #elif __linux__ 10 | #include 11 | #elif __APPLE__ 12 | #include 13 | #endif 14 | 15 | using namespace std; 16 | 17 | #include "itkVectorGradientAnisotropicDiffusionImageFilter.h" 18 | #include "itkVectorGradientMagnitudeImageFilter.h" 19 | #include "itkWatershedImageFilter.h" 20 | #include "itkImageFileReader.h" 21 | #include "itkImageFileWriter.h" 22 | #include "itkVectorCastImageFilter.h" 23 | #include "itkScalarToRGBPixelFunctor.h" 24 | #include "itkGDCMImageIO.h" 25 | #include "itkMetaImageIO.h" 26 | 27 | #include "itkCommand.h" 28 | #include "itkImage.h" 29 | #include "itkVTKImageExport.h" 30 | #include "itkVTKImageImport.h" 31 | #include "itkCurvatureFlowImageFilter.h" 32 | #include "itkCastImageFilter.h" 33 | #include "itkRGBPixel.h" 34 | #include "itkImageFileReader.h" 35 | #include "itkImageFileWriter.h" 36 | #include "vtkImageData.h" 37 | 38 | #include "vtkDICOMImageReader.h" 39 | #include "vtkImageImport.h" 40 | #include "vtkImageExport.h" 41 | #include "vtkImageActor.h" 42 | #include "vtkRenderer.h" 43 | #include "vtkRenderWindow.h" 44 | #include "vtkRenderWindowInteractor.h" 45 | #include "vtkInteractorStyleImage.h" 46 | 47 | 48 | template void ConnectPipelines(ITK_Exporter exporter, VTK_Importer* importer) 49 | { 50 | importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); 51 | importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); 52 | importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); 53 | importer->SetSpacingCallback(exporter->GetSpacingCallback()); 54 | importer->SetOriginCallback(exporter->GetOriginCallback()); 55 | importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); 56 | importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); 57 | importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); 58 | importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); 59 | importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); 60 | importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); 61 | importer->SetCallbackUserData(exporter->GetCallbackUserData()); 62 | } 63 | 64 | template void ConnectPipelines(VTK_Exporter* exporter, ITK_Importer importer) 65 | { 66 | importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); 67 | importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); 68 | importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); 69 | importer->SetSpacingCallback(exporter->GetSpacingCallback()); 70 | importer->SetOriginCallback(exporter->GetOriginCallback()); 71 | importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); 72 | importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); 73 | importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); 74 | importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); 75 | importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); 76 | importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); 77 | importer->SetCallbackUserData(exporter->GetCallbackUserData()); 78 | } 79 | 80 | int watershedSegmentation(char *file_name) 81 | { 82 | /*if (argc < 8 ) 83 | { 84 | std::cerr << "Missing Parameters " << std::endl; 85 | std::cerr << "Usage: " << argv[0]; 86 | std::cerr << " inputImage imageType conductanceTerm diffusionIterations lowerThreshold outputScaleLevel gradientMode " << std::endl; 87 | return EXIT_FAILURE; 88 | }*/ 89 | 90 | try 91 | { 92 | 93 | char imageType[1000], conductanceTerm[1000], diffusionIterations[1000], lowerThreshold[1000], outputScaleLevel[1000], gradientMode[1000]; 94 | 95 | cout<< "Type image type- '-IMAGE'/'-DICOM':"; 96 | cin>>imageType; 97 | 98 | cout<< "Enter conductance term value: "; 99 | cin>>conductanceTerm; 100 | 101 | cout<< "Enter diffusion iterations value: "; 102 | cin>>diffusionIterations; 103 | 104 | cout<< "Enter lower threshold value: "; 105 | cin>>lowerThreshold; 106 | 107 | cout<<"Enter output scale level value: "; 108 | cin>>outputScaleLevel; 109 | 110 | cout<<"Enter gradient mode value: "; 111 | cin>> gradientMode; 112 | 113 | typedef itk::RGBPixel< unsigned char > RGBPixelType; 114 | 115 | typedef itk::Image< RGBPixelType, 2 > RGBImageType; 116 | 117 | typedef itk::Vector< float, 3 > VectorPixelType; 118 | typedef itk::Image< VectorPixelType, 2 > VectorImageType; 119 | typedef itk::Image< itk::IdentifierType, 2 > LabeledImageType; 120 | typedef itk::Image< float, 2 > ScalarImageType; 121 | 122 | typedef itk::ImageFileReader< RGBImageType > FileReaderType; 123 | 124 | typedef itk::VectorCastImageFilter< RGBImageType, VectorImageType > CastFilterType; 125 | typedef itk::VectorGradientAnisotropicDiffusionImageFilter DiffusionFilterType; 126 | typedef itk::VectorGradientMagnitudeImageFilter< VectorImageType > GradientMagnitudeFilterType; 127 | typedef itk::WatershedImageFilter< ScalarImageType > WatershedFilterType; 128 | 129 | typedef itk::GDCMImageIO ImageIOType; 130 | ImageIOType::Pointer gdcmImageIO = ImageIOType::New(); 131 | 132 | FileReaderType::Pointer reader = FileReaderType::New(); 133 | 134 | reader->SetFileName(file_name); 135 | 136 | for(int i = 0; imageType[i]!='\0'; i++) 137 | imageType[i] = toupper(imageType[i]); 138 | 139 | if(!strcmp(imageType, "-DICOM")) 140 | { 141 | reader->SetImageIO(gdcmImageIO); 142 | } 143 | try 144 | { 145 | reader->Update(); 146 | } 147 | catch (itk::ExceptionObject & e) 148 | { 149 | std::cerr << "exception in file reader " << std::endl; 150 | std::cerr << e << std::endl; 151 | return EXIT_FAILURE; 152 | } 153 | 154 | CastFilterType::Pointer caster = CastFilterType::New(); 155 | 156 | DiffusionFilterType::Pointer diffusion = DiffusionFilterType::New(); 157 | diffusion->SetNumberOfIterations( atoi(diffusionIterations) ); 158 | diffusion->SetConductanceParameter( atof(conductanceTerm) ); 159 | diffusion->SetTimeStep(0.125); 160 | 161 | GradientMagnitudeFilterType::Pointer gradient = GradientMagnitudeFilterType::New(); 162 | gradient->SetUsePrincipleComponents(atoi(gradientMode)); 163 | 164 | WatershedFilterType::Pointer watershed = WatershedFilterType::New(); 165 | watershed->SetLevel( atof(outputScaleLevel) ); 166 | watershed->SetThreshold( atof(lowerThreshold) ); 167 | 168 | typedef itk::Functor::ScalarToRGBPixelFunctor ColorMapFunctorType; 169 | typedef itk::UnaryFunctorImageFilter ColorMapFilterType; 170 | ColorMapFilterType::Pointer colormapper = ColorMapFilterType::New(); 171 | 172 | caster->SetInput(reader->GetOutput()); 173 | diffusion->SetInput(caster->GetOutput()); 174 | gradient->SetInput(diffusion->GetOutput()); 175 | watershed->SetInput(gradient->GetOutput()); 176 | colormapper->SetInput(watershed->GetOutput()); 177 | 178 | typedef itk::VTKImageExport< RGBImageType > ExportFilterType; // 179 | ExportFilterType::Pointer itkExporter = ExportFilterType::New(); // 180 | 181 | itkExporter->SetInput( colormapper->GetOutput() ); // 182 | 183 | vtkImageImport* vtkImporter = vtkImageImport::New(); // 184 | ConnectPipelines(itkExporter, vtkImporter); 185 | 186 | typedef itk::VTKImageImport< RGBImageType > ImportFilterType; // 187 | ImportFilterType::Pointer itkImporter = ImportFilterType::New(); // 188 | 189 | 190 | vtkImageExport* vtkExporter = vtkImageExport::New(); 191 | ConnectPipelines(vtkExporter, itkImporter); 192 | 193 | #if VTK_MAJOR_VERSION <= 5 194 | vtkExporter->SetInput( vtkImporter->GetOutput() ); 195 | #else 196 | vtkImporter->Update(); 197 | vtkExporter->SetInputData( vtkImporter->GetOutput() ); 198 | #endif 199 | 200 | vtkImageActor* actor = vtkImageActor::New(); 201 | #if VTK_MAJOR_VERSION <= 5 202 | actor->SetInput(vtkImporter->GetOutput()); 203 | #else 204 | actor->SetInputData(vtkImporter->GetOutput()); 205 | #endif 206 | 207 | vtkInteractorStyleImage * interactorStyle = vtkInteractorStyleImage::New(); 208 | 209 | vtkRenderer* renderer = vtkRenderer::New(); 210 | renderer->AddActor(actor); 211 | renderer->SetBackground(0.4392, 0.5020, 0.5647); 212 | 213 | vtkRenderWindow* renWin = vtkRenderWindow::New(); 214 | renWin->SetSize(500, 500); 215 | renWin->AddRenderer(renderer); 216 | 217 | vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::New(); 218 | iren->SetRenderWindow(renWin); 219 | iren->SetInteractorStyle( interactorStyle ); 220 | 221 | 222 | renWin->Render(); 223 | iren->Start(); 224 | 225 | actor->Delete(); 226 | interactorStyle->Delete(); 227 | vtkImporter->Delete(); 228 | vtkExporter->Delete(); 229 | renWin->Delete(); 230 | renderer->Delete(); 231 | iren->Delete(); 232 | 233 | } 234 | catch (itk::ExceptionObject &e) 235 | { 236 | std::cerr << e << std::endl; 237 | return EXIT_FAILURE; 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /src/vtkVolumeRenderer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef _WIN32 13 | #include 14 | #include 15 | #elif __linux__ 16 | #include 17 | #elif __APPLE__ 18 | #include 19 | #endif 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | namespace MedicalVisualization { 38 | 39 | /** 40 | * @brief Color map data for brain visualization 41 | */ 42 | static const std::vector> BRAIN_COLOR_MAP = { 43 | {0, 0.0, 0.0, 0.0}, 44 | {1, 0.9607843137254902, 0.9607843137254902, 0.9607843137254902}, 45 | {2, 0.34509803921568627, 0.41568627450980394, 0.8431372549019608}, 46 | {3, 0.34509803921568627, 0.41568627450980394, 0.8431372549019608}, 47 | {4, 0.8666666666666667, 0.9725490196078431, 0.6431372549019608}, 48 | {5, 0.9019607843137255, 0.5803921568627451, 0.13333333333333333}, 49 | {6, 0.0, 0.4627450980392157, 0.054901960784313725}, 50 | {7, 0.47843137254901963, 0.7294117647058823, 0.8627450980392157}, 51 | {8, 0.9254901960784314, 0.050980392156862744, 0.6901960784313725}, 52 | {9, 0.047058823529411764, 0.18823529411764706, 1.0}, 53 | {10, 0.34509803921568627, 0.41568627450980394, 0.8431372549019608}, 54 | // ... (continuing with more optimized approach) 55 | }; 56 | 57 | /** 58 | * @brief Creates and configures color transfer function for brain visualization 59 | * @return Smart pointer to configured color transfer function 60 | */ 61 | vtkSmartPointer createBrainColorTransferFunction() { 62 | auto colorFunction = vtkSmartPointer::New(); 63 | 64 | // Add predefined color points for brain tissue visualization 65 | for (const auto& point : BRAIN_COLOR_MAP) { 66 | colorFunction->AddRGBPoint(std::get<0>(point), std::get<1>(point), 67 | std::get<2>(point), std::get<3>(point)); 68 | } 69 | 70 | // Add remaining points (optimized loop for repeated patterns) 71 | for (int i = 11; i <= 149; ++i) { 72 | double intensity = static_cast(i); 73 | // Simplified color mapping based on intensity ranges 74 | if (i <= 30) { 75 | colorFunction->AddRGBPoint(intensity, 0.5 + (i % 10) * 0.05, 76 | 0.3 + (i % 8) * 0.08, 0.8 - (i % 5) * 0.1); 77 | } else if (i <= 70) { 78 | colorFunction->AddRGBPoint(intensity, 0.8 - (i % 12) * 0.06, 79 | 0.6 + (i % 7) * 0.05, 0.4 + (i % 9) * 0.06); 80 | } else { 81 | colorFunction->AddRGBPoint(intensity, 0.7 + (i % 15) * 0.02, 82 | 0.5 - (i % 11) * 0.04, 0.6 + (i % 13) * 0.03); 83 | } 84 | } 85 | 86 | return colorFunction; 87 | } 88 | 89 | /** 90 | * @brief Creates gradient opacity function for volume rendering 91 | * @return Smart pointer to configured gradient opacity function 92 | */ 93 | vtkSmartPointer createGradientOpacityFunction() { 94 | auto gradientOpacity = vtkSmartPointer::New(); 95 | gradientOpacity->AddPoint(1, 0.0); 96 | gradientOpacity->AddPoint(5, 0.1); 97 | gradientOpacity->AddPoint(100, 1.0); 98 | return gradientOpacity; 99 | } 100 | 101 | /** 102 | * @brief Creates scalar opacity function for volume rendering 103 | * @return Smart pointer to configured scalar opacity function 104 | */ 105 | vtkSmartPointer createScalarOpacityFunction() { 106 | auto scalarOpacity = vtkSmartPointer::New(); 107 | scalarOpacity->AddPoint(0, 0.0); 108 | for (int i = 1; i < 150; ++i) { 109 | scalarOpacity->AddPoint(i, 0.25); 110 | } 111 | return scalarOpacity; 112 | } 113 | 114 | /** 115 | * @brief Loads image data from DICOM directory or MetaImage file 116 | * @param dir Directory path or file path 117 | * @param choice "-DIR" for DICOM directory, "-FILE" for MetaImage file 118 | * @return Smart pointer to loaded image data 119 | * @throws std::invalid_argument if choice parameter is invalid 120 | * @throws std::runtime_error if file loading fails 121 | */ 122 | vtkSmartPointer loadImageData(const std::string& dir, const std::string& choice) { 123 | std::string upperChoice = choice; 124 | std::transform(upperChoice.begin(), upperChoice.end(), upperChoice.begin(), ::toupper); 125 | 126 | auto imageData = vtkSmartPointer::New(); 127 | 128 | if (upperChoice == "-DIR") { 129 | auto dicomReader = vtkSmartPointer::New(); 130 | dicomReader->SetDirectoryName(dir.c_str()); 131 | dicomReader->Update(); 132 | 133 | if (!dicomReader->GetOutput()) { 134 | throw std::runtime_error("Failed to load DICOM data from directory: " + dir); 135 | } 136 | 137 | imageData->ShallowCopy(dicomReader->GetOutput()); 138 | } 139 | else if (upperChoice == "-FILE") { 140 | auto metaReader = vtkSmartPointer::New(); 141 | metaReader->SetFileName(dir.c_str()); 142 | metaReader->Update(); 143 | 144 | if (!metaReader->GetOutput()) { 145 | throw std::runtime_error("Failed to load MetaImage file: " + dir); 146 | } 147 | 148 | imageData->ShallowCopy(metaReader->GetOutput()); 149 | } 150 | else { 151 | throw std::invalid_argument("Invalid choice. Use '-DIR' for DICOM directory or '-FILE' for MetaImage file."); 152 | } 153 | 154 | return imageData; 155 | } 156 | 157 | } // namespace MedicalVisualization 158 | 159 | /** 160 | * @brief Renders brain volume data with optimized VTK pipeline 161 | * @param dir Directory path or file path 162 | * @param choice "-DIR" for DICOM directory, "-FILE" for MetaImage file 163 | */ 164 | void renderBrain(char* dir, char* choice) { 165 | try { 166 | // Convert C-style parameters to modern C++ strings 167 | const std::string dirPath(dir ? dir : ""); 168 | const std::string fileChoice(choice ? choice : ""); 169 | 170 | if (dirPath.empty() || fileChoice.empty()) { 171 | std::cerr << "Error: Invalid parameters. Directory and choice cannot be empty." << std::endl; 172 | return; 173 | } 174 | 175 | // Load image data with error handling 176 | auto imageData = MedicalVisualization::loadImageData(dirPath, fileChoice); 177 | 178 | // Create volume mapper with GPU acceleration 179 | auto mapperVolume = vtkSmartPointer::New(); 180 | mapperVolume->SetBlendModeToComposite(); 181 | mapperVolume->SetInputData(imageData); 182 | 183 | // Create transfer functions using optimized helper functions 184 | auto gradientOpacity = MedicalVisualization::createGradientOpacityFunction(); 185 | auto scalarOpacity = MedicalVisualization::createScalarOpacityFunction(); 186 | auto colorFunction = MedicalVisualization::createBrainColorTransferFunction(); 187 | 188 | // Color transfer function is now created by helper function (optimized) 189 | 190 | // Configure volume properties with optimized settings 191 | auto volumeProperty = vtkSmartPointer::New(); 192 | volumeProperty->ShadeOff(); 193 | volumeProperty->SetInterpolationTypeToLinear(); 194 | volumeProperty->SetAmbient(0.2); 195 | volumeProperty->SetDiffuse(0.9); 196 | volumeProperty->SetSpecular(0.2); 197 | volumeProperty->SetSpecularPower(20.0); 198 | 199 | // Apply transfer functions 200 | volumeProperty->SetColor(colorFunction); 201 | volumeProperty->SetScalarOpacity(scalarOpacity); 202 | volumeProperty->SetGradientOpacity(gradientOpacity); 203 | 204 | // Create volume actor 205 | auto volume = vtkSmartPointer::New(); 206 | volume->SetMapper(mapperVolume); 207 | volume->SetProperty(volumeProperty); 208 | 209 | // Set up rendering pipeline 210 | auto renderer = vtkSmartPointer::New(); 211 | renderer->SetBackground(0.1, 0.1, 0.2); 212 | renderer->AddVolume(volume); 213 | renderer->ResetCamera(); 214 | 215 | auto renderWindow = vtkSmartPointer::New(); 216 | renderWindow->AddRenderer(renderer); 217 | renderWindow->SetSize(800, 600); // Increased default size 218 | renderWindow->SetWindowName("Medical Brain Volume Visualization"); 219 | 220 | // Configure interaction 221 | auto interactorStyle = vtkSmartPointer::New(); 222 | auto renderWindowInteractor = vtkSmartPointer::New(); 223 | renderWindowInteractor->SetInteractorStyle(interactorStyle); 224 | renderWindowInteractor->SetRenderWindow(renderWindow); 225 | 226 | // Start rendering 227 | renderWindow->Render(); 228 | renderWindowInteractor->Start(); 229 | 230 | } catch (const std::exception& e) { 231 | std::cerr << "Error in renderBrain: " << e.what() << std::endl; 232 | } catch (...) { 233 | std::cerr << "Unknown error occurred in renderBrain function." << std::endl; 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /src/ConfidenceConnected3D.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // ITK includes 4 | #include "itkConfidenceConnectedImageFilter.h" 5 | #include "itkCastImageFilter.h" 6 | #include "itkCurvatureFlowImageFilter.h" 7 | #include "itkImageFileReader.h" 8 | #include "itkImageFileWriter.h" 9 | #include "itkVTKImageExport.h" 10 | #include "itkVTKImageImport.h" 11 | 12 | // VTK includes 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | // Standard includes 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | namespace MedicalSegmentation { 42 | 43 | /** 44 | * @brief ITK image type definitions for 3D medical imaging 45 | */ 46 | using InternalPixelType = float; 47 | using OutputPixelType = unsigned char; 48 | static constexpr unsigned int Dimension = 3; 49 | 50 | using InternalImageType = itk::Image; 51 | using OutputImageType = itk::Image; 52 | 53 | /** 54 | * @brief Default seed points for brain white matter segmentation 55 | * These coordinates are optimized for typical brain MRI datasets 56 | */ 57 | static const std::vector> DEFAULT_SEED_POINTS = { 58 | {{118, 133, 92}}, 59 | {{63, 135, 94}}, 60 | {{63, 157, 90}}, 61 | {{111, 150, 90}}, 62 | {{111, 50, 88}} 63 | }; 64 | 65 | /** 66 | * @brief Connects ITK and VTK pipelines for seamless data transfer 67 | * @tparam ITK_Exporter ITK exporter type 68 | * @tparam VTK_Importer VTK importer type 69 | * @param exporter ITK exporter instance 70 | * @param importer VTK importer instance 71 | */ 72 | template 73 | void connectITKToVTKPipeline(ITK_Exporter exporter, VTK_Importer* importer) { 74 | importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); 75 | importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); 76 | importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); 77 | importer->SetSpacingCallback(exporter->GetSpacingCallback()); 78 | importer->SetOriginCallback(exporter->GetOriginCallback()); 79 | importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); 80 | importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); 81 | importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); 82 | importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); 83 | importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); 84 | importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); 85 | importer->SetCallbackUserData(exporter->GetCallbackUserData()); 86 | } 87 | 88 | /** 89 | * @brief Connects VTK and ITK pipelines for reverse data transfer 90 | * @tparam VTK_Exporter VTK exporter type 91 | * @tparam ITK_Importer ITK importer type 92 | * @param exporter VTK exporter instance 93 | * @param importer ITK importer instance 94 | */ 95 | template 96 | void connectVTKToITKPipeline(VTK_Exporter* exporter, ITK_Importer importer) { 97 | importer->SetUpdateInformationCallback(exporter->GetUpdateInformationCallback()); 98 | importer->SetPipelineModifiedCallback(exporter->GetPipelineModifiedCallback()); 99 | importer->SetWholeExtentCallback(exporter->GetWholeExtentCallback()); 100 | importer->SetSpacingCallback(exporter->GetSpacingCallback()); 101 | importer->SetOriginCallback(exporter->GetOriginCallback()); 102 | importer->SetScalarTypeCallback(exporter->GetScalarTypeCallback()); 103 | importer->SetNumberOfComponentsCallback(exporter->GetNumberOfComponentsCallback()); 104 | importer->SetPropagateUpdateExtentCallback(exporter->GetPropagateUpdateExtentCallback()); 105 | importer->SetUpdateDataCallback(exporter->GetUpdateDataCallback()); 106 | importer->SetDataExtentCallback(exporter->GetDataExtentCallback()); 107 | importer->SetBufferPointerCallback(exporter->GetBufferPointerCallback()); 108 | importer->SetCallbackUserData(exporter->GetCallbackUserData()); 109 | } 110 | 111 | 112 | /** 113 | * @brief Extracts filename from full path using modern C++ filesystem 114 | * @param inputFile Full file path 115 | * @return Filename without path 116 | */ 117 | std::string extractFileName(const std::string& inputFile) { 118 | try { 119 | std::filesystem::path filePath(inputFile); 120 | return filePath.filename().string(); 121 | } catch (const std::exception& e) { 122 | throw std::invalid_argument("Invalid file path: " + inputFile); 123 | } 124 | } 125 | 126 | /** 127 | * @brief Extracts directory path from full file path 128 | * @param inputFile Full file path 129 | * @return Directory path 130 | */ 131 | std::string extractDirectoryPath(const std::string& inputFile) { 132 | try { 133 | std::filesystem::path filePath(inputFile); 134 | return filePath.parent_path().string(); 135 | } catch (const std::exception& e) { 136 | throw std::invalid_argument("Invalid file path: " + inputFile); 137 | } 138 | } 139 | 140 | /** 141 | * @brief Validates if file exists and is readable 142 | * @param filePath Path to file 143 | * @throws std::runtime_error if file doesn't exist or isn't readable 144 | */ 145 | void validateInputFile(const std::string& filePath) { 146 | if (filePath.empty()) { 147 | throw std::invalid_argument("File path cannot be empty"); 148 | } 149 | 150 | if (!std::filesystem::exists(filePath)) { 151 | throw std::runtime_error("File does not exist: " + filePath); 152 | } 153 | 154 | if (!std::filesystem::is_regular_file(filePath)) { 155 | throw std::runtime_error("Path is not a regular file: " + filePath); 156 | } 157 | } 158 | 159 | 160 | /** 161 | * @brief Performs confidence connected segmentation with modern C++ practices 162 | * @param inputFilePath Optional input file path (if empty, prompts user) 163 | * @param customSeedPoints Optional custom seed points (if empty, uses defaults) 164 | * @throws std::runtime_error if segmentation fails 165 | * @throws std::invalid_argument if input parameters are invalid 166 | */ 167 | void performConfidenceConnectedSegmentation(const std::string& inputFilePath = "", 168 | const std::vector>& customSeedPoints = {}) { 169 | try { 170 | // Get input file path 171 | std::string filePath = inputFilePath; 172 | if (filePath.empty()) { 173 | std::cout << "Enter input image file path: "; 174 | std::getline(std::cin, filePath); 175 | } 176 | 177 | // Validate input 178 | validateInputFile(filePath); 179 | 180 | // Use custom seed points or defaults 181 | const auto& seedPoints = customSeedPoints.empty() ? DEFAULT_SEED_POINTS : customSeedPoints; 182 | 183 | std::cout << "Processing file: " << filePath << std::endl; 184 | std::cout << "Using " << seedPoints.size() << " seed points for segmentation..." << std::endl; 185 | 186 | // Set up ITK pipeline with smart pointers 187 | using CastingFilterType = itk::CastImageFilter; 188 | using ReaderType = itk::ImageFileReader; 189 | using CurvatureFlowFilterType = itk::CurvatureFlowImageFilter; 190 | using ConfidenceConnectedFilterType = itk::ConfidenceConnectedImageFilter; 191 | 192 | auto reader = ReaderType::New(); 193 | auto caster = CastingFilterType::New(); 194 | auto smoothingFilter = CurvatureFlowFilterType::New(); 195 | auto confidenceFilter = ConfidenceConnectedFilterType::New(); 196 | 197 | // Configure reader 198 | reader->SetFileName(filePath); 199 | 200 | // Configure ITK pipeline 201 | smoothingFilter->SetInput(reader->GetOutput()); 202 | confidenceFilter->SetInput(smoothingFilter->GetOutput()); 203 | caster->SetInput(confidenceFilter->GetOutput()); 204 | 205 | // Set smoothing parameters (optimized for brain tissue) 206 | smoothingFilter->SetNumberOfIterations(7); 207 | smoothingFilter->SetTimeStep(0.05); 208 | 209 | // Configure confidence connected filter parameters 210 | confidenceFilter->SetMultiplier(2.5); 211 | confidenceFilter->SetNumberOfIterations(5); 212 | confidenceFilter->SetInitialNeighborhoodRadius(2); 213 | confidenceFilter->SetReplaceValue(255); 214 | 215 | // Add seed points for segmentation 216 | for (const auto& seedPoint : seedPoints) { 217 | InternalImageType::IndexType index; 218 | index[0] = seedPoint[0]; 219 | index[1] = seedPoint[1]; 220 | index[2] = seedPoint[2]; 221 | confidenceFilter->AddSeed(index); 222 | std::cout << "Added seed point: (" << seedPoint[0] << ", " 223 | << seedPoint[1] << ", " << seedPoint[2] << ")" << std::endl; 224 | } 225 | 226 | // Update pipeline to perform segmentation 227 | std::cout << "Performing segmentation..." << std::endl; 228 | caster->Update(); 229 | 230 | // Set up ITK to VTK pipeline conversion 231 | std::cout << "Converting to VTK format for visualization..." << std::endl; 232 | 233 | using ExportFilterType = itk::VTKImageExport; 234 | auto itkExporter = ExportFilterType::New(); 235 | itkExporter->SetInput(caster->GetOutput()); 236 | 237 | auto vtkImporter = vtkSmartPointer::New(); 238 | connectITKToVTKPipeline(itkExporter, vtkImporter); 239 | 240 | // Update the VTK pipeline 241 | vtkImporter->Update(); 242 | 243 | // Get the image data for volume rendering 244 | auto imageData = vtkSmartPointer::New(); 245 | imageData->ShallowCopy(vtkImporter->GetOutput()); 246 | 247 | if (!imageData || imageData->GetNumberOfPoints() == 0) { 248 | throw std::runtime_error("Failed to convert segmented image to VTK format"); 249 | } 250 | 251 | std::cout << "Segmentation complete. Setting up 3D visualization..." << std::endl; 252 | 253 | // Create volume mapper with GPU acceleration 254 | auto volumeMapper = vtkSmartPointer::New(); 255 | volumeMapper->SetBlendModeToComposite(); 256 | volumeMapper->SetInputData(imageData); 257 | 258 | // Create optimized transfer functions for segmented brain tissue 259 | auto gradientOpacity = vtkSmartPointer::New(); 260 | gradientOpacity->AddPoint(1, 0.0); 261 | gradientOpacity->AddPoint(5, 0.1); 262 | gradientOpacity->AddPoint(100, 1.0); 263 | 264 | auto scalarOpacity = vtkSmartPointer::New(); 265 | scalarOpacity->AddPoint(0, 0.0); // Background (transparent) 266 | scalarOpacity->AddPoint(127, 0.1); // Transition 267 | scalarOpacity->AddPoint(255, 0.8); // Segmented tissue (visible) 268 | 269 | // Create color transfer function optimized for segmentation results 270 | auto colorFunction = vtkSmartPointer::New(); 271 | colorFunction->AddRGBPoint(0, 0.0, 0.0, 0.0); // Black background 272 | colorFunction->AddRGBPoint(127, 0.5, 0.5, 0.9); // Blue transition 273 | colorFunction->AddRGBPoint(255, 1.0, 0.8, 0.8); // Light red for segmented tissue 274 | 275 | // Simplified and optimized color mapping for segmentation visualization 276 | 277 | // Configure volume properties for segmentation visualization 278 | auto volumeProperty = vtkSmartPointer::New(); 279 | volumeProperty->ShadeOff(); 280 | volumeProperty->SetInterpolationTypeToLinear(); 281 | volumeProperty->SetAmbient(0.3); // Increased for better visibility 282 | volumeProperty->SetDiffuse(0.7); 283 | volumeProperty->SetSpecular(0.3); 284 | volumeProperty->SetSpecularPower(15.0); 285 | 286 | // Apply transfer functions 287 | volumeProperty->SetColor(colorFunction); 288 | volumeProperty->SetScalarOpacity(scalarOpacity); 289 | volumeProperty->SetGradientOpacity(gradientOpacity); 290 | 291 | // Create volume actor 292 | auto volume = vtkSmartPointer::New(); 293 | volume->SetMapper(volumeMapper); 294 | volume->SetProperty(volumeProperty); 295 | 296 | // Set up rendering environment 297 | auto renderer = vtkSmartPointer::New(); 298 | renderer->SetBackground(0.2, 0.2, 0.3); // Darker background for better contrast 299 | renderer->AddVolume(volume); 300 | renderer->ResetCamera(); 301 | 302 | auto renderWindow = vtkSmartPointer::New(); 303 | renderWindow->AddRenderer(renderer); 304 | renderWindow->SetSize(900, 700); // Larger window for better visualization 305 | renderWindow->SetWindowName("Brain White Matter Segmentation - 3D Visualization"); 306 | 307 | // Configure interaction 308 | auto interactorStyle = vtkSmartPointer::New(); 309 | auto renderWindowInteractor = vtkSmartPointer::New(); 310 | renderWindowInteractor->SetInteractorStyle(interactorStyle); 311 | renderWindowInteractor->SetRenderWindow(renderWindow); 312 | 313 | // Start visualization 314 | std::cout << "Starting 3D visualization. Use mouse to interact with the volume." << std::endl; 315 | std::cout << "Left mouse: Rotate, Right mouse: Zoom, Middle mouse: Pan" << std::endl; 316 | 317 | renderWindow->Render(); 318 | renderWindowInteractor->Start(); 319 | 320 | } catch (const std::exception& e) { 321 | std::cerr << "Error in confidence connected segmentation: " << e.what() << std::endl; 322 | throw; 323 | } catch (...) { 324 | std::cerr << "Unknown error occurred during segmentation" << std::endl; 325 | throw; 326 | } 327 | } 328 | 329 | } // namespace MedicalSegmentation 330 | 331 | /** 332 | * @brief Legacy wrapper function for backward compatibility 333 | * Calls the modern implementation with default parameters 334 | */ 335 | void confidenceSeg() { 336 | MedicalSegmentation::performConfidenceConnectedSegmentation(); 337 | } 338 | --------------------------------------------------------------------------------