├── .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 |
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 |
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 |
--------------------------------------------------------------------------------