├── README(en-us).md ├── sample ├── Dentascan 0.75 H60s-CT-3-57.dcm ├── Dentascan 0.75 H60s-CT-3-58.dcm ├── Dentascan 0.75 H60s-CT-3-59.dcm ├── Dentascan 0.75 H60s-CT-3-60.dcm ├── Dentascan 0.75 H60s-CT-3-61.dcm ├── Dentascan 0.75 H60s-CT-3-62.dcm ├── Dentascan 0.75 H60s-CT-3-63.dcm ├── Dentascan 0.75 H60s-CT-3-64.dcm ├── Dentascan 0.75 H60s-CT-3-65.dcm ├── Dentascan 0.75 H60s-CT-3-66.dcm ├── Dentascan 0.75 H60s-CT-3-67.dcm ├── Dentascan 0.75 H60s-CT-3-68.dcm ├── Dentascan 0.75 H60s-CT-3-69.dcm ├── Dentascan 0.75 H60s-CT-3-70.dcm ├── Dentascan 0.75 H60s-CT-3-71.dcm ├── Dentascan 0.75 H60s-CT-3-72.dcm ├── Dentascan 0.75 H60s-CT-3-73.dcm ├── Dentascan 0.75 H60s-CT-3-74.dcm ├── Dentascan 0.75 H60s-CT-3-75.dcm ├── Dentascan 0.75 H60s-CT-3-76.dcm ├── Dentascan 0.75 H60s-CT-3-77.dcm ├── Dentascan 0.75 H60s-CT-3-78.dcm ├── Dentascan 0.75 H60s-CT-3-79.dcm ├── Dentascan 0.75 H60s-CT-3-80.dcm ├── Dentascan 0.75 H60s-CT-3-81.dcm ├── Dentascan 0.75 H60s-CT-3-82.dcm ├── Dentascan 0.75 H60s-CT-3-83.dcm └── Dentascan 0.75 H60s-CT-3-84.dcm ├── LICENSE.md └── main.py /README(en-us).md: -------------------------------------------------------------------------------- 1 | # vtkDicomRender 2 | Python source to view a DICOM image in 3D and save to stl 3 | 4 | -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-57.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-57.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-58.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-58.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-59.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-59.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-60.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-60.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-61.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-61.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-62.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-62.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-63.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-63.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-64.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-64.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-65.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-65.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-66.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-66.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-67.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-67.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-68.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-68.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-69.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-69.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-70.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-70.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-71.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-71.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-72.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-72.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-73.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-73.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-74.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-74.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-75.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-75.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-76.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-76.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-77.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-77.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-78.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-78.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-79.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-79.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-80.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-80.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-81.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-81.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-82.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-82.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-83.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-83.dcm -------------------------------------------------------------------------------- /sample/Dentascan 0.75 H60s-CT-3-84.dcm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gabrielmini/vtkDicomRender/HEAD/sample/Dentascan 0.75 H60s-CT-3-84.dcm -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from vtk import * 2 | from vtk.wx.wxVTKRenderWindowInteractor import wxVTKRenderWindowInteractor 3 | import thread 4 | import wx 5 | import pydicom 6 | import os 7 | 8 | class VtkPanel(wx.Panel): 9 | 10 | def __init__(self, parent): 11 | wx.Panel.__init__(self, parent) 12 | self.parent = parent 13 | 14 | # Top Sizer Configuration 15 | self.topSizer = wx.BoxSizer(wx.HORIZONTAL) 16 | 17 | self.IMAGE_PATH = None 18 | self.ROOT_PIPE = None 19 | self.DICOM_IMAGES = None 20 | self.FIRST_IMAGE = None 21 | self.IMAGE_LARGEST_PIXEL = None 22 | self.IMAGE_SMALLEST_PIXEL = None 23 | 24 | self.loadView() # Loading View 25 | 26 | # Initializing 27 | self.wxThresholdRadioBox.SetSelection(0) 28 | self.wxLowerSlider.Disable() 29 | 30 | 31 | def loadView(self): 32 | # LEFT 33 | #self.InteractorImageRenderWindow = wxVTKRenderWindowInteractor(self, -1) 34 | #self.InteractorImageRenderWindow.Enable(1) 35 | 36 | #self.topSizer.Add(self.InteractorImageRenderWindow, 1, wx.EXPAND| wx.RIGHT, 5) 37 | #self.ImageViewer = vtkImageViewer2() 38 | 39 | #a = wx.Panel(self, -1) 40 | #a.SetBackgroundColour("#00FF00") 41 | #self.topSizer.Add(a,1,wx.EXPAND|wx.RIGHT, 5) 42 | #self.wxImageSlider = wx.Slider(self, -1, style=wx.SL_VERTICAL | wx.SL_LEFT | wx.SL_MIN_MAX_LABELS | wx.EXPAND) 43 | #self.topSizer.Add(self.wxImageSlider, 0, wx.EXPAND) 44 | 45 | 46 | # RIGHT 47 | self.Interactor3DRenderWindow = wxVTKRenderWindowInteractor(self,-1) 48 | self.Interactor3DRenderWindow.Enable(1) 49 | 50 | self.topSizer.Add(self.Interactor3DRenderWindow, 1, wx.EXPAND) 51 | 52 | # Botton Sizer Configuration 53 | self.bottomSizer = wx.BoxSizer(wx.HORIZONTAL) 54 | 55 | # Load and Save Section 56 | self.loadSaveStaticBox = wx.StaticBox(self, -1, "Load and Save") 57 | self.wxLoadSaveStaticBox = wx.StaticBoxSizer(self.loadSaveStaticBox, wx.VERTICAL) 58 | self.wxLoadButton = wx.Button(self, -1, "Load Image", size=(100, 40)) 59 | self.wxLoadSaveStaticBox.Add(self.wxLoadButton, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 10) 60 | self.wxSaveButton = wx.Button(self, -1, "Save Volume", size=(100, 40)) 61 | self.wxLoadSaveStaticBox.Add(self.wxSaveButton, 1, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 10) 62 | self.bottomSizer.Add(self.wxLoadSaveStaticBox, 0, wx.EXPAND | wx.RIGHT, 10) 63 | 64 | # Configuration Section 65 | self.configurationStaticBox = wx.StaticBox(self, -1, "Configuration") 66 | self.wxConfigurationStaticBox = wx.StaticBoxSizer(self.configurationStaticBox, wx.VERTICAL) 67 | self.wxThresholdRadioBox = wx.RadioBox(self, -1, "Threshold Configuration", (-1, -1), (-1, -1), ["Upper", "Lower", "Range"], 3, wx.RA_SPECIFY_COLS) 68 | 69 | self.wxConfigurationStaticBox.Add(self.wxThresholdRadioBox, 0, wx.EXPAND | wx.ALL, 5) 70 | self.bottomSizer.Add(self.wxConfigurationStaticBox, 1, wx.EXPAND) 71 | 72 | # Sliders 73 | self.wxLowerStaticText = wx.StaticText(self, -1, "Lower: 0") 74 | self.wxConfigurationStaticBox.Add(self.wxLowerStaticText, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 1) 75 | self.wxLowerSlider = wx.Slider(self, -1, minValue=0, maxValue=100) 76 | self.wxConfigurationStaticBox.Add(self.wxLowerSlider, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 1) 77 | self.wxUpperStaticText = wx.StaticText(self, -1, "Upper: 0") 78 | self.wxConfigurationStaticBox.Add(self.wxUpperStaticText, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 1) 79 | self.wxUpperSlider = wx.Slider(self, -1, minValue=0, maxValue=100) 80 | self.wxConfigurationStaticBox.Add(self.wxUpperSlider, 0, wx.EXPAND | wx.LEFT | wx.RIGHT, 1) 81 | 82 | # Filter Section 83 | self.filterStaticBox = wx.StaticBox(self, -1, "Filters") 84 | self.wxFilterStaticBox = wx.StaticBoxSizer(self.filterStaticBox, wx.VERTICAL) 85 | self.bottomSizer.Add(self.wxFilterStaticBox, 1, wx.EXPAND|wx.LEFT,10) 86 | 87 | # Root Sizer Configuration 88 | self.rootSizer = wx.BoxSizer(wx.VERTICAL) 89 | 90 | self.rootSizer.Add(self.topSizer, 2, wx.EXPAND | wx.ALL, 10) 91 | self.rootSizer.Add(self.bottomSizer, 1, wx.EXPAND | wx.ALL, 10) 92 | 93 | self.SetSizer(self.rootSizer) 94 | self.Layout() 95 | 96 | #Status Bar 97 | # Implement 98 | 99 | # Binds 100 | self.wxLoadButton.Bind(wx.EVT_BUTTON, self.OnButtonLoadImageClick) 101 | 102 | self.wxThresholdRadioBox.Bind(wx.EVT_RADIOBOX, self.OnWxThresholdRadioBoxChanged) 103 | self.wxUpperSlider.Bind(wx.EVT_SLIDER, self.OnWxUpperSliderChanged) 104 | self.wxLowerSlider.Bind(wx.EVT_SLIDER, self.OnWxLowerSliderChanged) 105 | 106 | # States 107 | self.wxSaveButton.Disable() 108 | 109 | self.loadSaveStaticBox.Disable() 110 | self.wxThresholdRadioBox.Disable() 111 | self.wxUpperSlider.Disable() 112 | 113 | 114 | 115 | 116 | def OnWxThresholdRadioBoxChanged(self, evt): 117 | selection = evt.Int 118 | 119 | self.wxLowerSlider.Disable() 120 | self.wxUpperSlider.Disable() 121 | 122 | if selection == 0: # Upper 123 | self.wxUpperSlider.Enable() 124 | self.wxLowerStaticText.SetLabel("Lower: 0") 125 | self.wxLowerSlider.SetValue(0) 126 | 127 | elif selection == 1: # Lower 128 | self.wxLowerSlider.Enable() 129 | self.wxUpperStaticText.SetLabel("Upper: 0") 130 | self.wxUpperSlider.SetValue(0) 131 | 132 | elif selection == 2: # Range 133 | self.wxLowerSlider.Enable() 134 | self.wxUpperSlider.Enable() 135 | else: 136 | raise NotImplementedError() 137 | 138 | def OnWxUpperSliderChanged(self, evt): 139 | self.wxUpperStaticText.SetLabel("Upper: " +str(self.wxUpperSlider.GetValue())) 140 | 141 | def OnWxLowerSliderChanged(self, evt): 142 | self.wxLowerStaticText.SetLabel("Lower: " + str(self.wxLowerSlider.GetValue())) 143 | 144 | 145 | def showImage(self,imageData): 146 | raise NotImplementedError() 147 | self.ImageViewer.SeInputConnection(imageData.GetOutputPort()) 148 | self.ImageViewer.SetupInteractor(self.InteractorImageRenderWindow) 149 | 150 | self.ImageViewer.Render() 151 | 152 | def OnButtonLoadImageClick(self, evt): 153 | dirDialog = wx.DirDialog(self, 154 | message="Select a Folder with Dicom Files", 155 | defaultPath=r"C:\Projects\IC\sample", # Temporary 156 | #defaultPath=r"C:\Users\work\Desktop\dicoms\old\dentalTeste", # Temporary 157 | style=wx.DD_DEFAULT_STYLE,) 158 | 159 | if dirDialog.ShowModal() == wx.ID_OK: 160 | self.loadDicomImages(dirDialog.GetPath()) 161 | #self.wxSaveButton.Enable() 162 | 163 | 164 | dirDialog.Destroy() 165 | 166 | 167 | def loadDicomImages(self, dicomFilesPath): 168 | 169 | # TODO Implement verification if dicom files exists 170 | dicomPath = os.path.join(dicomFilesPath, os.listdir(dicomFilesPath)[1]) 171 | try: 172 | dicomFile = pydicom.read_file(dicomPath) 173 | except Exception as e: 174 | raise e 175 | 176 | if 0x00280106 in dicomFile and 0x00280107 in dicomFile: 177 | self.IMAGE_SMALLEST_PIXEL = dicomFile[0x00280106].value # SmallestImagePixelValue 178 | self.IMAGE_LARGEST_PIXEL = dicomFile[0x00280107].value # LargestImagePixelValue 179 | else: 180 | self.IMAGE_SMALLEST_PIXEL = 0 181 | self.IMAGE_LARGEST_PIXEL = 100 182 | 183 | self.wxUpperSlider.SetRange(self.IMAGE_SMALLEST_PIXEL, self.IMAGE_LARGEST_PIXEL) 184 | self.wxLowerSlider.SetRange(self.IMAGE_SMALLEST_PIXEL, self.IMAGE_LARGEST_PIXEL) 185 | self.wxLowerSlider.Update() 186 | self.Layout() 187 | 188 | dicomImages = vtkDICOMImageReader() 189 | dicomImages.SetDirectoryName(dicomFilesPath) 190 | dicomImages.Update() 191 | 192 | self.DICOM_IMAGES = dicomImages 193 | self.adjustImageThreshold(800) 194 | #self.__plotImage(self.ROOT_PIPE) 195 | self.createVolume() 196 | self.decimateVolume(0.5) 197 | self.view3DImage(self.ROOT_PIPE) 198 | 199 | # View 200 | #self.wxConfigurationStaticBox.Enable() 201 | #self.wxFilterStaticBox.Enable() 202 | 203 | def createVolume(self): 204 | mesh_3d = vtkDiscreteMarchingCubes() 205 | mesh_3d.SetInputConnection(self.ROOT_PIPE.GetOutputPort()) 206 | mesh_3d.GenerateValues(1, 1, 1) 207 | mesh_3d.Update() 208 | self.ROOT_PIPE = mesh_3d 209 | 210 | 211 | def __plotImage(self, imageData): 212 | raise NotImplementedError() 213 | self.ImageViewer.SetInputConnection(imageData.GetOutputPort()) 214 | self.ImageViewer.SetupInteractor(self.InteractorImageRenderWindow) 215 | 216 | self.ImageViewer.Render() 217 | self.InteractorImageRenderWindow.Start() 218 | 219 | 220 | def adjustImageThreshold(self, lower_limit=None, upper_value=None): 221 | 222 | thresholdFilter = vtkImageThreshold() 223 | thresholdFilter.SetInputConnection(self.DICOM_IMAGES.GetOutputPort()) 224 | 225 | if lower_limit is not None and upper_value is not None: # Threshold By Range 226 | if lower_limit > upper_value: 227 | temp_value = upper_value 228 | upper_value = lower_limit 229 | lower_limit = temp_value 230 | thresholdFilter.ThresholdBetween(lower_limit, upper_value) 231 | 232 | elif lower_limit is not None and upper_value is None: # Threshold By lower 233 | thresholdFilter.ThresholdByLower(lower_limit) 234 | 235 | elif upper_value is not None and lower_limit is None: # Threshold By Upper 236 | thresholdFilter.ThresholdByUpper(upper_value) 237 | 238 | else: 239 | thresholdFilter.ThresholdByLower(255) 240 | 241 | thresholdFilter.SetInValue(0) 242 | thresholdFilter.ReplaceInOn() 243 | #thresholdFilter.SetOutValue(1) 244 | thresholdFilter.SetOutValue(1) 245 | thresholdFilter.ReplaceOutOn() 246 | thresholdFilter.Update() 247 | 248 | thresholdFilter.Update() 249 | self.ROOT_PIPE = thresholdFilter 250 | self.FIRST_IMAGE = thresholdFilter 251 | 252 | return thresholdFilter 253 | 254 | 255 | 256 | def saveStlFile(self, file_name="3d_volume"): 257 | writer = vtkSTLWriter() 258 | writer.SetInputConnection(self.ROOT_PIPE.GetOutputPort()) 259 | writer.SetFileTypeToBinary() 260 | writer.SetFileName("".join([file_name, ".stl"])) 261 | writer.Write() 262 | 263 | def gaussianFilter(self, imageData): 264 | gaussianFilter = vtkImageGaussianSmooth() 265 | gaussianFilter.SetInputConnection(imageData.GetOutputPort()) 266 | gaussianFilter.Update() 267 | return gaussianFilter 268 | 269 | def fillHoles(self): 270 | fillHolesFilter = vtkFillHolesFilter() 271 | fillHolesFilter.SetInputConnection(self.ROOT_PIPE.GetOutputPort()) 272 | fillHolesFilter.SetHoleSize(1000.0) 273 | 274 | dataFixed = vtkPolyDataNormals() 275 | dataFixed.SetInputConnection(fillHolesFilter.GetOutputPort()) 276 | dataFixed.ConsistencyOn() 277 | dataFixed.SplittingOff() 278 | dataFixed.Update() 279 | self.ROOT_PIPE = dataFixed 280 | return dataFixed 281 | 282 | def smoothVolume(self, type="laplacian", level=1): 283 | smooth = None 284 | 285 | if type == "laplacian": 286 | smooth = vtkSmoothPolyDataFilter() 287 | smooth.SetNumberOfIterations(level) 288 | 289 | elif type == "linear": 290 | smooth = vtkLinearSubdivisionFilter() 291 | smooth.SetNumberOfSubdivisions(level) 292 | 293 | elif type == "loop": 294 | smooth = vtkLoopSubdivisionFilter() 295 | smooth.SetNumberOfSubdivisions(level) 296 | 297 | elif type == "butterfly": 298 | smooth = vtkButterflySubdivisionFilter() 299 | smooth.SetNumberOfSubdivisions(level) 300 | 301 | else: 302 | print "Invalid Type assuming Laplacian" 303 | self.smoothVolume(type="laplacian", level=level) 304 | return 305 | 306 | smooth.SetInputConnection(self.ROOT_PIPE.GetOutputPort()) 307 | smooth.Update() 308 | self.ROOT_PIPE = smooth 309 | 310 | def decimateVolume(self, reduction=0.1): 311 | if not 0 < reduction < 1: 312 | reduction = 0.3 # 30% 313 | 314 | decimatedVolume = vtkDecimatePro() 315 | decimatedVolume.SetInputConnection(self.ROOT_PIPE.GetOutputPort()) 316 | decimatedVolume.SetTargetReduction(reduction) 317 | decimatedVolume.Update() 318 | self.ROOT_PIPE = decimatedVolume 319 | 320 | def view3DImage(self, imageData): 321 | polyDataMapper = vtkPolyDataMapper() 322 | polyDataMapper.ImmediateModeRenderingOn() 323 | polyDataMapper.SetInputConnection(imageData.GetOutputPort()) 324 | 325 | polyDataMapper.Update() 326 | 327 | volume_3d = vtkActor() 328 | volume_3d.SetMapper(polyDataMapper) 329 | volume_3d.GetProperty().SetColor(0,0,1) 330 | 331 | renderer = vtkRenderer() 332 | renderer.AddActor(volume_3d) 333 | renderer.SetBackground(1.0, 1.0, 1.0) # White 334 | 335 | self.Interactor3DRenderWindow.GetRenderWindow().AddRenderer(renderer) 336 | self.Layout() 337 | #self.InteractorRenderWindow.GetRenderWindow().SetSize(500,500) 338 | #self.InteractorRenderWindow.Initialize() 339 | 340 | #self.InteractorRenderWindow.GetRenderWindow().Render() 341 | #self.InteractorRenderWindow.Start() 342 | 343 | 344 | def main(): 345 | 346 | app = wx.App() 347 | 348 | main_frame = wx.Frame(None, size=(800,600)) 349 | 350 | sizer = wx.BoxSizer(wx.VERTICAL) 351 | main_frame.SetSizer(sizer) 352 | 353 | frame = VtkPanel(main_frame) 354 | sizer.Add(frame,1,wx.EXPAND) 355 | 356 | main_frame.Show() 357 | main_frame.CenterOnScreen() 358 | app.MainLoop() 359 | 360 | if __name__ == "__main__": 361 | main() 362 | 363 | 364 | 365 | 366 | 367 | --------------------------------------------------------------------------------