|
a |
|
b/CLI/IntervertebralAnalysis/IntervertebralAnalysis.py |
|
|
1 |
#!/usr/bin/env python-real |
|
|
2 |
|
|
|
3 |
import sys |
|
|
4 |
import os |
|
|
5 |
from datetime import date |
|
|
6 |
|
|
|
7 |
import numpy as np |
|
|
8 |
|
|
|
9 |
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) |
|
|
10 |
from MusculoskeletalAnalysisCLITools import ( |
|
|
11 |
crop, |
|
|
12 |
readImg, |
|
|
13 |
readMask, |
|
|
14 |
width, |
|
|
15 |
writeReport, |
|
|
16 |
) |
|
|
17 |
|
|
|
18 |
|
|
|
19 |
OUTPUT_FIELDS = [ |
|
|
20 |
("Date Analysis Performed", "The current date"), |
|
|
21 |
("Input Volume", "Name of the input volume"), |
|
|
22 |
("Disc Volume (mm^3)", "The volume of the disc"), |
|
|
23 |
("Nucleus Pulposus Volume (mm^3)", "The volume of the NP"), |
|
|
24 |
("Volume Ratio", "The ratio of whole disc volume to NP volume"), |
|
|
25 |
("Annulus Fibrosus Width (mm)", "The width of the AF, calculated by using rotating calipers algorithm on each slice and finding the maximum width"), |
|
|
26 |
("Nucleus Pulposus Width (mm)", "The width of the NP, calculated using the same method as AF width"), |
|
|
27 |
("Disc Height (mm)", "The height of the disc at its center"), |
|
|
28 |
("Disc Height Ratio", "The ratio of disc height to disc width"), |
|
|
29 |
("Voxel Dimension (mm)", "The side length of one voxel, measured in milimeters"), |
|
|
30 |
] |
|
|
31 |
|
|
|
32 |
|
|
|
33 |
def main(inputImg, inputMask1, inputMask2, voxSize, name, output): |
|
|
34 |
imgData = readImg(inputImg) |
|
|
35 |
(_, maskData1) = readMask(inputMask1) |
|
|
36 |
(_, maskData2) = readMask(inputMask2) |
|
|
37 |
# Set the np mask to the smaller one |
|
|
38 |
if np.count_nonzero(maskData1) > np.count_nonzero(maskData2): |
|
|
39 |
(maskData, npData, imgData) = crop(maskData1, maskData2, imgData) |
|
|
40 |
else: |
|
|
41 |
(maskData, npData, imgData) = crop(maskData2, maskData1, imgData) |
|
|
42 |
(maskData, npData, imgData) = crop(maskData, npData, imgData) |
|
|
43 |
if np.count_nonzero(maskData) == 0 or np.count_nonzero(npData) == 0: |
|
|
44 |
raise Exception("Segmentation mask is empty.") |
|
|
45 |
|
|
|
46 |
volume = np.count_nonzero(maskData) * voxSize**3 |
|
|
47 |
npVolume = np.count_nonzero(npData) * voxSize**3 |
|
|
48 |
vr = npVolume/volume |
|
|
49 |
|
|
|
50 |
print("""<filter-progress>{}</filter-progress>""".format(.33)) |
|
|
51 |
sys.stdout.flush() |
|
|
52 |
|
|
|
53 |
afWidth= width(maskData) * voxSize |
|
|
54 |
npWidth = width(npData) * voxSize |
|
|
55 |
|
|
|
56 |
# Find the center |
|
|
57 |
xcent = int(np.rint(np.mean(np.nonzero(maskData)[0]))) |
|
|
58 |
ycent = int(np.rint(np.mean(np.nonzero(maskData[1])))) |
|
|
59 |
center = np.nonzero(maskData[xcent,ycent,:]) |
|
|
60 |
height = (np.max(center)-np.min(center)) * voxSize |
|
|
61 |
|
|
|
62 |
hw = height/afWidth |
|
|
63 |
|
|
|
64 |
print("""<filter-progress>{}</filter-progress>""".format(.66)) |
|
|
65 |
sys.stdout.flush() |
|
|
66 |
|
|
|
67 |
fPath = os.path.join(output, "intervertebral.txt") |
|
|
68 |
header = [field[0] for field in OUTPUT_FIELDS] |
|
|
69 |
data = [ |
|
|
70 |
date.today(), |
|
|
71 |
name, |
|
|
72 |
volume, |
|
|
73 |
npVolume, |
|
|
74 |
vr, |
|
|
75 |
afWidth, |
|
|
76 |
npWidth, |
|
|
77 |
height, |
|
|
78 |
hw, |
|
|
79 |
voxSize |
|
|
80 |
] |
|
|
81 |
|
|
|
82 |
writeReport(fPath, header, data) |
|
|
83 |
|
|
|
84 |
|
|
|
85 |
|
|
|
86 |
if __name__ == "__main__": |
|
|
87 |
if len(sys.argv) < 7: |
|
|
88 |
print(sys.argv) |
|
|
89 |
print("Usage: Intervertebral Analysis <input> <mask1> <mask2> <voxelSize> <name> <output>") |
|
|
90 |
sys.exit(1) |
|
|
91 |
main(sys.argv[1], sys.argv[2], sys.argv[3], float(sys.argv[4]), str(sys.argv[5]), str(sys.argv[6])) |
|
|
92 |
|