-
Notifications
You must be signed in to change notification settings - Fork 2
/
GenerateObj.py
183 lines (158 loc) · 7.81 KB
/
GenerateObj.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
import os
import shlex
from __main__ import vtk, qt, ctk, slicer
import SampleData
from ROBEXBrainExtraction import ROBEXBrainExtractionLogic
class GenerateObj:
def __init__(self, parent):
parent.title = "Generate Obj Model"
parent.categories = ["Surface Models"]
parent.dependencies = []
parent.contributors = ["Mingrui Jiang"]
parent.helpText = """
Run this script to generate .obj file models for specific nifti files inside a folder structure
Make sure you install the ROBEX brain extraction module first
"""
parent.acknowledgementText = """
Thanks to youtube and the opensource community for teaching me the way of 3D Slicer scripting.
"""
self.parent = parent
class GenerateObjWidget:
def __init__(self, parent=None):
if not parent:
self.parent = slicer.qMRMLWidget()
self.parent.setLayout(qt.QVBoxLayout())
self.parent.setMRMLScene(slicer.mrmlScene)
else:
self.parent = parent
self.layout = self.parent.layout()
if not parent:
self.setup()
self.parent.show()
def setup(self):
collapsibleButton = ctk.ctkCollapsibleButton()
collapsibleButton.text = "Robex Brain Extraction"
self.layout.addWidget(collapsibleButton)
self.formLayout = qt.QFormLayout(collapsibleButton)
self.formFrame = qt.QFrame(collapsibleButton)
self.formFrame.setLayout(qt.QHBoxLayout())
self.formLayout.addWidget(self.formFrame)
# folder text field
# will search under this folder and 1 level below this folder
self.textfield = qt.QTextEdit()
self.formLayout.addRow("folder", self.textfield)
# input file name text field
# will search for files matching this name
self.brainfileTextfield = qt.QTextEdit()
self.formLayout.addRow("input files", self.brainfileTextfield)
button = qt.QPushButton("Generate brain.obj and brainmask.nii")
button.connect("clicked(bool)", self.robexBrainExtractionButtonClicked)
self.formLayout.addRow(button)
# output file name
# input file names and output file names will match line by line
self.brainOutputTextfield = qt.QTextEdit()
self.formLayout.addRow("output files", self.brainOutputTextfield)
collapsibleButtonB = ctk.ctkCollapsibleButton()
collapsibleButtonB.text = "Tumor Segmentation"
self.layout.addWidget(collapsibleButtonB)
self.formLayoutB = qt.QFormLayout(collapsibleButtonB)
self.formFrameB = qt.QFrame(collapsibleButtonB)
self.formFrameB.setLayout(qt.QHBoxLayout())
self.formLayoutB.addWidget(self.formFrameB)
self.textfieldB = qt.QTextEdit()
self.formLayoutB.addRow("folder", self.textfieldB)
self.segmentationfileTextfield = qt.QTextEdit()
self.formLayoutB.addRow("input files", self.segmentationfileTextfield)
buttonB = qt.QPushButton("Generate segmentation.obj")
buttonB.connect("clicked(bool)", self.informationButtonClicked)
self.formLayoutB.addRow(buttonB)
self.segmentationOutputTextfield = qt.QTextEdit()
self.formLayoutB.addRow("output files", self.segmentationOutputTextfield)
def robexBrainExtractionButtonClicked(self):
print "robex button clicked"
text = self.textfield.toPlainText()
folders = shlex.split(text)
print folders
fileName = self.brainfileTextfield.toPlainText()
filenames = shlex.split(fileName)
print filenames
outputName = self.brainOutputTextfield.toPlainText()
outputnames = shlex.split(outputName)
print outputnames
for folder in folders:
subdirs = [x[0] for x in os.walk(folder)]
for subdir in subdirs:
for filename, outputname in zip(filenames, outputnames):
filepath = os.path.join(subdir, filename)
if not os.path.isfile(filepath):
continue
[success, loadedVolumeNode] = slicer.util.loadVolume(filepath, returnNode=True)
robexLogic = ROBEXBrainExtractionLogic()
outputNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLLabelMapVolumeNode')
brainNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLScalarVolumeNode')
robexLogic.run(loadedVolumeNode, brainNode, outputNode)
#slicer.util.saveNode(brainNode, os.path.join(subdir, outputname+'.nii'))
slicer.util.saveNode(outputNode, os.path.join(subdir, outputname+'mask.nii'))
self.CreateSegmentation(outputNode, os.path.join(subdir, outputname+'.obj'))
print "finish"
def informationButtonClicked(self):
print "segmentation button clicked"
text = self.textfieldB.toPlainText()
folders = shlex.split(text)
print folders
fileName = self.segmentationfileTextfield.toPlainText()
filenames = shlex.split(fileName)
print filenames
outputName = self.segmentationOutputTextfield.toPlainText()
outputnames = shlex.split(outputName)
print outputnames
for folder in folders:
subdirs = [x[0] for x in os.walk(folder)]
for subdir in subdirs:
print(subdir)
for filename, outputname in zip(filenames, outputnames):
filepath = os.path.join(subdir, filename)
if not os.path.isfile(filepath):
continue
[success, loadedVolumeNode] = slicer.util.loadVolume(filepath, returnNode=True)
sampleDataLogic = SampleData.SampleDataLogic()
masterVolumeNode = loadedVolumeNode
self.CreateSegmentation(masterVolumeNode, os.path.join(subdir, outputname))
print 'finish'
def CreateSegmentation(self, masterVolumeNode, outputObj):
# Create segmentation
segmentationNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentationNode")
segmentationNode.CreateDefaultDisplayNodes() # only needed for display
segmentationNode.SetReferenceImageGeometryParameterFromVolumeNode(masterVolumeNode)
addedSegmentID = segmentationNode.GetSegmentation().AddEmptySegment("segmentation")
# Create segment editor to get access to effects
segmentEditorWidget = slicer.qMRMLSegmentEditorWidget()
segmentEditorWidget.setMRMLScene(slicer.mrmlScene)
segmentEditorNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentEditorNode")
segmentEditorWidget.setMRMLSegmentEditorNode(segmentEditorNode)
segmentEditorWidget.setSegmentationNode(segmentationNode)
segmentEditorWidget.setMasterVolumeNode(masterVolumeNode)
# Thresholding
segmentEditorWidget.setActiveEffectByName("Threshold")
effect = segmentEditorWidget.activeEffect()
effect.setParameter("MinimumThreshold","1")
effect.setParameter("MaximumThreshold","999")
effect.self().onApply()
# Clean up
segmentEditorWidget = None
slicer.mrmlScene.RemoveNode(segmentEditorNode)
# Make segmentation results visible in 3D
segmentationNode.CreateClosedSurfaceRepresentation()
# Make sure surface mesh cells are consistently oriented
surfaceMesh = segmentationNode.GetClosedSurfaceRepresentation(addedSegmentID)
normals = vtk.vtkPolyDataNormals()
normals.AutoOrientNormalsOn()
normals.ConsistencyOn()
normals.SetInputData(surfaceMesh)
normals.Update()
surfaceMesh = normals.GetOutput()
# Write to OBJ file
writer = vtk.vtkOBJWriter()
writer.SetInputData(surfaceMesh)
writer.SetFileName(outputObj)
writer.Update()