├── .gitignore ├── DicomVis.py ├── DicomVis_ui.py ├── LICENSE ├── MainWindow.py ├── MainWindow_ui.py ├── README.md ├── __init__.py ├── __init__.pyc ├── doc └── Raport.pdf └── ui ├── DicomVis.ui ├── MainWindow.ui └── ui_to_py.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Sphinx documentation 57 | docs/_build/ 58 | 59 | # PyBuilder 60 | target/ 61 | 62 | # IPython Notebook 63 | .ipynb_checkpoints 64 | 65 | # pyenv 66 | .python-version 67 | -------------------------------------------------------------------------------- /DicomVis.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = 'MKozuch' 4 | 5 | 6 | # TODO: podpiac suwaki do callbacka 7 | # TODO: ustawiz dobre zakresy na suwakach okienkowania 8 | # TODO: opakowac w zewnetrzny interfejs 9 | # TODO: rozkminic metode na kolorowanie przedzialow 10 | # TODO: dobrze sie bawic 11 | 12 | import vtk 13 | from PyQt4 import QtGui, QtCore 14 | from DicomVis_ui import Ui_Form 15 | 16 | 17 | try: 18 | from lib import StudyData as StudyData 19 | from lib import VisuAnalysisWidget 20 | except(ImportError): 21 | class VisuAnalysisWidget(QtGui.QWidget): 22 | pass 23 | 24 | 25 | class DicomVis(VisuAnalysisWidget): 26 | 27 | def __init__(self, parent = None): 28 | 29 | self.reader = vtk.vtkDICOMImageReader() 30 | self.dataExtent = [] 31 | self.dataDimensions = [] 32 | self.dataRange = () 33 | 34 | # initialize GUI 35 | QtGui.QWidget.__init__(self, parent) 36 | self.ui = Ui_Form() 37 | self.ui.setupUi(self) 38 | self.ui.WindowCenterSlider.setRange(0, 1000) 39 | self.ui.WindowWidthSlider.setRange(0, 1000) 40 | 41 | # define viewers 42 | [self.viewerXY, self.viewerYZ, self.viewerXZ] = [vtk.vtkImageViewer2() for x in range(3)] 43 | 44 | # attach interactors to viewers 45 | self.viewerXY.SetupInteractor(self.ui.XYPlaneWidget) 46 | self.viewerYZ.SetupInteractor(self.ui.YZPlaneWidget) 47 | self.viewerXZ.SetupInteractor(self.ui.XZPlaneWidget) 48 | 49 | # set render windows for viewers 50 | self.viewerXY.SetRenderWindow(self.ui.XYPlaneWidget.GetRenderWindow()) 51 | self.viewerYZ.SetRenderWindow(self.ui.YZPlaneWidget.GetRenderWindow()) 52 | self.viewerXZ.SetRenderWindow(self.ui.XZPlaneWidget.GetRenderWindow()) 53 | 54 | # set slicing orientation for viewers 55 | self.viewerXY.SetSliceOrientationToXZ() 56 | self.viewerYZ.SetSliceOrientationToYZ() 57 | self.viewerXZ.SetSliceOrientationToXY() 58 | 59 | # rotate image 60 | act = self.viewerYZ.GetImageActor() 61 | act.SetOrientation(90, 0, 0) 62 | 63 | # setup volume rendering 64 | self.volRender = vtk.vtkRenderer() 65 | self.volRenWin = self.ui.VolumeWidget.GetRenderWindow() 66 | self.volRenWin.AddRenderer(self.volRender) 67 | 68 | self.rayCastFunction = vtk.vtkVolumeRayCastCompositeFunction() 69 | self.volumeMapper = vtk.vtkVolumeRayCastMapper() 70 | self.volumeMapper.SetVolumeRayCastFunction(self.rayCastFunction) 71 | 72 | volumeColor = vtk.vtkColorTransferFunction() 73 | volumeColor.AddRGBPoint(0, 0.0, 0.0, 0.0) 74 | volumeColor.AddRGBPoint(500, 1.0, 0.5, 0.3) 75 | volumeColor.AddRGBPoint(1000, 1.0, 0.5, 0.3) 76 | volumeColor.AddRGBPoint(1150, 1.0, 1.0, 0.9) 77 | self.volumeColor = volumeColor 78 | 79 | volumeScalarOpacity = vtk.vtkPiecewiseFunction() 80 | volumeScalarOpacity.AddPoint(0, 0.00) 81 | volumeScalarOpacity.AddPoint(50, 0.15) 82 | volumeScalarOpacity.AddPoint(100, 0.15) 83 | volumeScalarOpacity.AddPoint(115, 0.85) 84 | self.volumeScalarOpacity = volumeScalarOpacity 85 | 86 | volumeGradientOpacity = vtk.vtkPiecewiseFunction() 87 | volumeGradientOpacity.AddPoint(0, 0.0) 88 | volumeGradientOpacity.AddPoint(100, 0.5) 89 | volumeGradientOpacity.AddPoint(500, 1) 90 | self.volumeGradientOpacity = volumeGradientOpacity 91 | 92 | volumeProperty = vtk.vtkVolumeProperty() 93 | volumeProperty.SetColor(volumeColor) 94 | volumeProperty.SetScalarOpacity(volumeScalarOpacity) 95 | volumeProperty.SetGradientOpacity(volumeGradientOpacity) 96 | volumeProperty.SetInterpolationTypeToLinear() 97 | volumeProperty.ShadeOn() 98 | volumeProperty.SetAmbient(0.4) 99 | volumeProperty.SetDiffuse(0.6) 100 | volumeProperty.SetSpecular(0.2) 101 | self.volumeProperty = volumeProperty 102 | 103 | volume = vtk.vtkVolume() 104 | volume.SetMapper(self.volumeMapper) 105 | volume.SetProperty(self.volumeProperty) 106 | self.volume = volume 107 | 108 | self.volRender.AddViewProp(volume) 109 | 110 | 111 | 112 | def updateData(self, studydata): 113 | self.load_study_from_path(studydata.getPath()) 114 | 115 | 116 | def load_study_from_path(self, studyPath): 117 | 118 | # Update reader 119 | self.reader.SetDirectoryName(studyPath) 120 | self.reader.Update() 121 | 122 | self.xyMapper = vtk.vtk 123 | 124 | # Get data dimensionality 125 | self.dataExtent = self.reader.GetDataExtent() 126 | dataDimensionX = self.dataExtent[1]-self.dataExtent[0] 127 | dataDimensionY = self.dataExtent[3]-self.dataExtent[2] 128 | dataDimensionZ = self.dataExtent[5]-self.dataExtent[4] 129 | self.dataDimensions = [dataDimensionX, dataDimensionY, dataDimensionZ] 130 | 131 | # Calculate index of middle slice 132 | midslice1 = int((self.dataExtent[1]-self.dataExtent[0])/2 + self.dataExtent[0]) 133 | midslice2 = int((self.dataExtent[3]-self.dataExtent[2])/2 + self.dataExtent[2]) 134 | midslice3 = int((self.dataExtent[5]-self.dataExtent[4])/2 + self.dataExtent[4]) 135 | 136 | # Calculate enter 137 | center = [midslice1, midslice2, midslice3] 138 | 139 | # Get data range 140 | self.dataRange = self.reader.GetOutput().GetPointData().GetArray("DICOMImage").GetRange() 141 | print(self.dataRange) 142 | 143 | # Set current slice to the middle one 144 | for pair in zip([self.viewerXY, self.viewerYZ, self.viewerXZ], [midslice1, midslice2, midslice3]): 145 | pair[0].SetInputData(self.reader.GetOutput()) 146 | pair[0].SetSlice(pair[1]) 147 | pair[0].Render() 148 | pass 149 | 150 | # Set range and proper value for slice sliders 151 | for pair in zip([self.ui.XYSlider, self.ui.YZSlider, self.ui.XZSlider,], self.dataDimensions, [midslice1, midslice2, midslice3]): 152 | pair[0].setRange(0, pair[1]) 153 | pair[0].setValue(pair[2]) 154 | 155 | # Set range and value for windowing sliders 156 | self.ui.WindowCenterSlider.setRange(int(self.dataRange[0]), int(self.dataRange[1])) 157 | self.ui.WindowWidthSlider.setRange(1, int(self.dataRange[1])) 158 | 159 | # set input for volume renderer 160 | self.volumeMapper.SetInputConnection(self.reader.GetOutputPort()) 161 | self.volRenWin.Render() 162 | 163 | 164 | # setup slots for slicing sliders 165 | @QtCore.pyqtSlot(int) 166 | def on_XYSlider_valueChanged(self, value): 167 | self.viewerXY.SetSlice(value) 168 | 169 | @QtCore.pyqtSlot(int) 170 | def on_YZSlider_valueChanged(self, value): 171 | self.viewerYZ.SetSlice(value) 172 | 173 | @QtCore.pyqtSlot(int) 174 | def on_XZSlider_valueChanged(self, value): 175 | self.viewerXZ.SetSlice(value) 176 | 177 | 178 | # Setup slots for windowing sliders 179 | @QtCore.pyqtSlot(int) 180 | def on_WindowCenterSlider_valueChanged(self, value): 181 | for x in [self.viewerXY, self.viewerXZ, self.viewerYZ]: 182 | x.SetColorLevel(value) 183 | x.Render() 184 | 185 | @QtCore.pyqtSlot(int) 186 | def on_WindowWidthSlider_valueChanged(self, value): 187 | for x in [self.viewerXY, self.viewerXZ, self.viewerYZ]: 188 | x.SetColorWindow(value) 189 | x.Render() 190 | 191 | 192 | if __name__ == "__main__": 193 | import sys 194 | app = QtGui.QApplication(sys.argv) 195 | window = DicomVis() 196 | print(type(window)) 197 | window.show() 198 | 199 | studyPath = "C:\\DICOM_resources\\BRAINIX\\T1-3D-FFE-C - 801" 200 | window.load_study_from_path(studyPath) 201 | exitStatus = app.exec_() 202 | #del(window) 203 | sys.exit(exitStatus) 204 | -------------------------------------------------------------------------------- /DicomVis_ui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'DicomVis.ui' 4 | # 5 | # Created: Thu Feb 18 11:03:07 2016 6 | # by: PyQt4 UI code generator 4.11.3 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PyQt4 import QtCore, QtGui 11 | 12 | try: 13 | _fromUtf8 = QtCore.QString.fromUtf8 14 | except AttributeError: 15 | def _fromUtf8(s): 16 | return s 17 | 18 | try: 19 | _encoding = QtGui.QApplication.UnicodeUTF8 20 | def _translate(context, text, disambig): 21 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 22 | except AttributeError: 23 | def _translate(context, text, disambig): 24 | return QtGui.QApplication.translate(context, text, disambig) 25 | 26 | class Ui_Form(object): 27 | def setupUi(self, Form): 28 | Form.setObjectName(_fromUtf8("Form")) 29 | Form.resize(647, 480) 30 | self.horizontalLayout = QtGui.QHBoxLayout(Form) 31 | self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout")) 32 | self.gridLayout_2 = QtGui.QGridLayout() 33 | self.gridLayout_2.setSizeConstraint(QtGui.QLayout.SetMinimumSize) 34 | self.gridLayout_2.setContentsMargins(0, -1, -1, 0) 35 | self.gridLayout_2.setHorizontalSpacing(6) 36 | self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) 37 | self.verticalLayout = QtGui.QVBoxLayout() 38 | self.verticalLayout.setSpacing(6) 39 | self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) 40 | self.label = QtGui.QLabel(Form) 41 | self.label.setObjectName(_fromUtf8("label")) 42 | self.verticalLayout.addWidget(self.label) 43 | self.XYPlaneWidget = QVTKRenderWindowInteractor(Form) 44 | self.XYPlaneWidget.setObjectName(_fromUtf8("XYPlaneWidget")) 45 | self.verticalLayout.addWidget(self.XYPlaneWidget) 46 | self.XYSlider = QtGui.QSlider(Form) 47 | self.XYSlider.setOrientation(QtCore.Qt.Horizontal) 48 | self.XYSlider.setObjectName(_fromUtf8("XYSlider")) 49 | self.verticalLayout.addWidget(self.XYSlider) 50 | self.verticalLayout.setStretch(1, 1) 51 | self.gridLayout_2.addLayout(self.verticalLayout, 0, 0, 1, 1) 52 | self.verticalLayout_2 = QtGui.QVBoxLayout() 53 | self.verticalLayout_2.setObjectName(_fromUtf8("verticalLayout_2")) 54 | self.label_3 = QtGui.QLabel(Form) 55 | self.label_3.setObjectName(_fromUtf8("label_3")) 56 | self.verticalLayout_2.addWidget(self.label_3) 57 | self.YZPlaneWidget = QVTKRenderWindowInteractor(Form) 58 | self.YZPlaneWidget.setObjectName(_fromUtf8("YZPlaneWidget")) 59 | self.verticalLayout_2.addWidget(self.YZPlaneWidget) 60 | self.YZSlider = QtGui.QSlider(Form) 61 | self.YZSlider.setOrientation(QtCore.Qt.Horizontal) 62 | self.YZSlider.setObjectName(_fromUtf8("YZSlider")) 63 | self.verticalLayout_2.addWidget(self.YZSlider) 64 | self.verticalLayout_2.setStretch(1, 1) 65 | self.gridLayout_2.addLayout(self.verticalLayout_2, 0, 1, 1, 1) 66 | self.verticalLayout_3 = QtGui.QVBoxLayout() 67 | self.verticalLayout_3.setObjectName(_fromUtf8("verticalLayout_3")) 68 | self.label_2 = QtGui.QLabel(Form) 69 | self.label_2.setObjectName(_fromUtf8("label_2")) 70 | self.verticalLayout_3.addWidget(self.label_2) 71 | self.XZPlaneWidget = QVTKRenderWindowInteractor(Form) 72 | self.XZPlaneWidget.setObjectName(_fromUtf8("XZPlaneWidget")) 73 | self.verticalLayout_3.addWidget(self.XZPlaneWidget) 74 | self.XZSlider = QtGui.QSlider(Form) 75 | self.XZSlider.setOrientation(QtCore.Qt.Horizontal) 76 | self.XZSlider.setObjectName(_fromUtf8("XZSlider")) 77 | self.verticalLayout_3.addWidget(self.XZSlider) 78 | self.verticalLayout_3.setStretch(1, 1) 79 | self.gridLayout_2.addLayout(self.verticalLayout_3, 1, 0, 1, 1) 80 | self.verticalLayout_5 = QtGui.QVBoxLayout() 81 | self.verticalLayout_5.setObjectName(_fromUtf8("verticalLayout_5")) 82 | self.label_4 = QtGui.QLabel(Form) 83 | self.label_4.setObjectName(_fromUtf8("label_4")) 84 | self.verticalLayout_5.addWidget(self.label_4) 85 | self.VolumeWidget = QVTKRenderWindowInteractor(Form) 86 | self.VolumeWidget.setObjectName(_fromUtf8("VolumeWidget")) 87 | self.verticalLayout_5.addWidget(self.VolumeWidget) 88 | self.verticalLayout_5.setStretch(1, 1) 89 | self.gridLayout_2.addLayout(self.verticalLayout_5, 1, 1, 1, 1) 90 | self.horizontalLayout.addLayout(self.gridLayout_2) 91 | self.gridLayout = QtGui.QGridLayout() 92 | self.gridLayout.setSizeConstraint(QtGui.QLayout.SetDefaultConstraint) 93 | self.gridLayout.setObjectName(_fromUtf8("gridLayout")) 94 | self.WindowWidthLabel = QtGui.QLabel(Form) 95 | self.WindowWidthLabel.setObjectName(_fromUtf8("WindowWidthLabel")) 96 | self.gridLayout.addWidget(self.WindowWidthLabel, 2, 0, 1, 1) 97 | self.WindowWidthSlider = QtGui.QSlider(Form) 98 | self.WindowWidthSlider.setOrientation(QtCore.Qt.Horizontal) 99 | self.WindowWidthSlider.setObjectName(_fromUtf8("WindowWidthSlider")) 100 | self.gridLayout.addWidget(self.WindowWidthSlider, 2, 1, 1, 1) 101 | self.WindowControlLabel = QtGui.QLabel(Form) 102 | self.WindowControlLabel.setFrameShape(QtGui.QFrame.NoFrame) 103 | self.WindowControlLabel.setAlignment(QtCore.Qt.AlignCenter) 104 | self.WindowControlLabel.setObjectName(_fromUtf8("WindowControlLabel")) 105 | self.gridLayout.addWidget(self.WindowControlLabel, 0, 0, 1, 1) 106 | self.WindowCenterLabel = QtGui.QLabel(Form) 107 | self.WindowCenterLabel.setObjectName(_fromUtf8("WindowCenterLabel")) 108 | self.gridLayout.addWidget(self.WindowCenterLabel, 1, 0, 1, 1) 109 | self.WindowCenterSlider = QtGui.QSlider(Form) 110 | self.WindowCenterSlider.setOrientation(QtCore.Qt.Horizontal) 111 | self.WindowCenterSlider.setObjectName(_fromUtf8("WindowCenterSlider")) 112 | self.gridLayout.addWidget(self.WindowCenterSlider, 1, 1, 1, 1) 113 | spacerItem = QtGui.QSpacerItem(20, 40, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding) 114 | self.gridLayout.addItem(spacerItem, 3, 0, 1, 1) 115 | self.horizontalLayout.addLayout(self.gridLayout) 116 | self.horizontalLayout.setStretch(0, 3) 117 | self.horizontalLayout.setStretch(1, 1) 118 | 119 | self.retranslateUi(Form) 120 | QtCore.QMetaObject.connectSlotsByName(Form) 121 | 122 | def retranslateUi(self, Form): 123 | Form.setWindowTitle(_translate("Form", "DICOM Visualizer", None)) 124 | self.label.setText(_translate("Form", "XY slice", None)) 125 | self.label_3.setText(_translate("Form", "YZ slice", None)) 126 | self.label_2.setText(_translate("Form", "XZ slice", None)) 127 | self.label_4.setText(_translate("Form", "Volume render", None)) 128 | self.WindowWidthLabel.setText(_translate("Form", "Color window", None)) 129 | self.WindowControlLabel.setText(_translate("Form", "Window control", None)) 130 | self.WindowCenterLabel.setText(_translate("Form", "Color level", None)) 131 | 132 | from vtk.qt4.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor 133 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2018, Michal Kozuch 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /MainWindow.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | __author__ = 'MKozuch' 4 | 5 | from PyQt4 import QtCore, QtGui 6 | from DicomVis import DicomVis 7 | from MainWindow_ui import Ui_MainWindow 8 | 9 | 10 | class MainWindow(QtGui.QMainWindow): 11 | def __init__(self, parent=None): 12 | QtGui.QMainWindow.__init__(self, parent) 13 | self.ui = Ui_MainWindow() 14 | self.ui.setupUi(self) 15 | 16 | self.dicomVisWidget = DicomVis() 17 | self.ui.verticalLayout.insertWidget(0, self.dicomVisWidget) 18 | 19 | studypath = "C:\\DICOM_resources\\BRAINIX\\T1-3D-FFE-C - 801" 20 | self.dicomVisWidget.load_study_from_path(studypath) 21 | 22 | @QtCore.pyqtSlot() 23 | def on_loadStudyBtn_clicked(self): 24 | dicompath = str(QtGui.QFileDialog.getExistingDirectory(None, "Open Directory", "/home", QtGui.QFileDialog.ShowDirsOnly)) 25 | try: 26 | self.dicomVisWidget.load_study_from_path(dicompath) 27 | except: 28 | infobox = QtGui.QMessageBox(QtGui.QMessageBox.Critical, "Error", "Ups! Something went wrong") 29 | infobox.exec_() 30 | 31 | 32 | @QtCore.pyqtSlot() 33 | def on_actionAbout_triggered(self): 34 | infobox = QtGui.QMessageBox(QtGui.QMessageBox.Information, "About", "by: MKozuch") 35 | infobox.exec_() 36 | 37 | if __name__ == "__main__": 38 | import sys 39 | app = QtGui.QApplication(sys.argv) 40 | window = MainWindow() 41 | window.show() 42 | exitCode = app.exec_() 43 | sys.exit(exitCode) 44 | 45 | 46 | -------------------------------------------------------------------------------- /MainWindow_ui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'MainWindow.ui' 4 | # 5 | # Created: Sun Feb 14 16:53:14 2016 6 | # by: PyQt4 UI code generator 4.11.3 7 | # 8 | # WARNING! All changes made in this file will be lost! 9 | 10 | from PyQt4 import QtCore, QtGui 11 | 12 | try: 13 | _fromUtf8 = QtCore.QString.fromUtf8 14 | except AttributeError: 15 | def _fromUtf8(s): 16 | return s 17 | 18 | try: 19 | _encoding = QtGui.QApplication.UnicodeUTF8 20 | def _translate(context, text, disambig): 21 | return QtGui.QApplication.translate(context, text, disambig, _encoding) 22 | except AttributeError: 23 | def _translate(context, text, disambig): 24 | return QtGui.QApplication.translate(context, text, disambig) 25 | 26 | class Ui_MainWindow(object): 27 | def setupUi(self, MainWindow): 28 | MainWindow.setObjectName(_fromUtf8("MainWindow")) 29 | MainWindow.resize(800, 600) 30 | self.centralwidget = QtGui.QWidget(MainWindow) 31 | self.centralwidget.setObjectName(_fromUtf8("centralwidget")) 32 | self.gridLayout = QtGui.QGridLayout(self.centralwidget) 33 | self.gridLayout.setObjectName(_fromUtf8("gridLayout")) 34 | self.verticalLayout = QtGui.QVBoxLayout() 35 | self.verticalLayout.setObjectName(_fromUtf8("verticalLayout")) 36 | self.placeholderWidget = QtGui.QWidget(self.centralwidget) 37 | self.placeholderWidget.setObjectName(_fromUtf8("placeholderWidget")) 38 | self.gridLayout_2 = QtGui.QGridLayout(self.placeholderWidget) 39 | self.gridLayout_2.setMargin(0) 40 | self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2")) 41 | self.verticalLayout.addWidget(self.placeholderWidget) 42 | self.loadStudyBtn = QtGui.QPushButton(self.centralwidget) 43 | self.loadStudyBtn.setFlat(False) 44 | self.loadStudyBtn.setObjectName(_fromUtf8("loadStudyBtn")) 45 | self.verticalLayout.addWidget(self.loadStudyBtn) 46 | self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1) 47 | MainWindow.setCentralWidget(self.centralwidget) 48 | self.menubar = QtGui.QMenuBar(MainWindow) 49 | self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21)) 50 | self.menubar.setObjectName(_fromUtf8("menubar")) 51 | self.menuHelp = QtGui.QMenu(self.menubar) 52 | self.menuHelp.setObjectName(_fromUtf8("menuHelp")) 53 | MainWindow.setMenuBar(self.menubar) 54 | self.statusbar = QtGui.QStatusBar(MainWindow) 55 | self.statusbar.setObjectName(_fromUtf8("statusbar")) 56 | MainWindow.setStatusBar(self.statusbar) 57 | self.actionAbout = QtGui.QAction(MainWindow) 58 | self.actionAbout.setObjectName(_fromUtf8("actionAbout")) 59 | self.menuHelp.addAction(self.actionAbout) 60 | self.menubar.addAction(self.menuHelp.menuAction()) 61 | 62 | self.retranslateUi(MainWindow) 63 | QtCore.QMetaObject.connectSlotsByName(MainWindow) 64 | 65 | def retranslateUi(self, MainWindow): 66 | MainWindow.setWindowTitle(_translate("MainWindow", "DicomVis", None)) 67 | self.loadStudyBtn.setText(_translate("MainWindow", "Load Study", None)) 68 | self.menuHelp.setTitle(_translate("MainWindow", "Help", None)) 69 | self.actionAbout.setText(_translate("MainWindow", "About", None)) 70 | 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DicomVis 2 | Simple 4-pane viewer for visualising series of DICOM images. Written in Python using VTK. 3 | Requires VTK and PyQt4 4 | 5 | -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- 1 | from DicomVis import DicomVis as DicomVis -------------------------------------------------------------------------------- /__init__.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MKozuch/DicomVis/407b08a3a75c1e9d0bb6ae7c0603345d00817411/__init__.pyc -------------------------------------------------------------------------------- /doc/Raport.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MKozuch/DicomVis/407b08a3a75c1e9d0bb6ae7c0603345d00817411/doc/Raport.pdf -------------------------------------------------------------------------------- /ui/DicomVis.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 647 10 | 480 11 | 12 | 13 | 14 | DICOM Visualizer 15 | 16 | 17 | 18 | 19 | 20 | QLayout::SetMinimumSize 21 | 22 | 23 | 0 24 | 25 | 26 | 0 27 | 28 | 29 | 6 30 | 31 | 32 | 33 | 34 | 6 35 | 36 | 37 | 38 | 39 | XY slice 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | Qt::Horizontal 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | YZ slice 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | Qt::Horizontal 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | XZ slice 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | Qt::Horizontal 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | Volume render 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | QLayout::SetDefaultConstraint 117 | 118 | 119 | 120 | 121 | Color window 122 | 123 | 124 | 125 | 126 | 127 | 128 | Qt::Horizontal 129 | 130 | 131 | 132 | 133 | 134 | 135 | QFrame::NoFrame 136 | 137 | 138 | Window control 139 | 140 | 141 | Qt::AlignCenter 142 | 143 | 144 | 145 | 146 | 147 | 148 | Color level 149 | 150 | 151 | 152 | 153 | 154 | 155 | Qt::Horizontal 156 | 157 | 158 | 159 | 160 | 161 | 162 | Qt::Vertical 163 | 164 | 165 | 166 | 20 167 | 40 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | QVTKWidget 179 | QWidget 180 |
QVTKWidget.h
181 |
182 |
183 | 184 | 185 |
186 | -------------------------------------------------------------------------------- /ui/MainWindow.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 800 10 | 600 11 | 12 | 13 | 14 | DicomVis 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | Load Study 29 | 30 | 31 | false 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 0 43 | 0 44 | 800 45 | 21 46 | 47 | 48 | 49 | 50 | Help 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | About 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /ui/ui_to_py.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | ''' this script is used to convert Qt *.ui file to PyQt UI class 4 | in order to mae it compatibile with vtk bindings for Python ''' 5 | 6 | 7 | import os 8 | import sys 9 | 10 | fileIn = sys.argv[1] 11 | 12 | if len(sys.argv) == 3: 13 | fileOut = sys.argv[2] 14 | elif len(sys.argv) == 2: 15 | fileOut = sys.argv[1].split('.')[0] + "_ui.py" 16 | 17 | fileTemp = '_temp.py' 18 | 19 | command = "pyuic4 -o {} {}".format(fileTemp, fileIn) 20 | print('Generating {} from {}'.format(fileOut, fileIn)) 21 | print('Executing command: ' + command) 22 | os.system(command) 23 | 24 | # Need to do some substitution in generated file to make the UI work in python 25 | # when the QVTKWidget was created to be used in C++ 26 | 27 | f = open(fileTemp, 'r') 28 | s = f.read() 29 | f.close() 30 | 31 | s = s.replace('QVTKWidget','QVTKRenderWindowInteractor') 32 | s = s.replace('from QVTK', 'from vtk.qt4.QVTK') 33 | 34 | w = open(fileOut, 'w') 35 | w.write(s) 36 | w.close() 37 | 38 | os.remove(fileTemp) 39 | 40 | print('Done') 41 | --------------------------------------------------------------------------------