Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 47 additions & 28 deletions DeepSlice.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@
import pandas as pd
import numpy as np


class DeepSlice:
def __init__(self, weights=None):
self.weights = weights

def Build(self):
def Build(self, xception_weights="xception_weights_tf_dim_ordering_tf_kernels.h5"):
# Download Xception architecture with weights pretrained on imagenet
DenseModel = Xception(include_top=True, weights='xception_weights_tf_dim_ordering_tf_kernels.h5')
DenseModel = Xception(include_top=True, weights=xception_weights)
# remove the Dense Softmax layer and average pooling layer from the pretrained model
DenseModel._layers.pop()
DenseModel._layers.pop()
Expand All @@ -23,11 +24,11 @@ def Build(self):
model.add(DenseModel)
# we tested various sizes for these last two layers but consistently found that 256 performed best for some unknown reason.
# theoretically larger layers should be better able to fit the training set but this is not what we saw.
model.add(Dense(256, activation='relu'))
model.add(Dense(256, activation='relu'))
model.add(Dense(256, activation="relu"))
model.add(Dense(256, activation="relu"))
# as we are predicting continuous values, here we define 9 output neurons with linear activation functions,
# each corresponding to one of the QuickNII alignment variables Oxyz, Uxyz, Vxyz.
model.add(Dense(9, activation='linear'))
model.add(Dense(9, activation="linear"))
if self.weights != None:
# load weights
model.load_weights(self.weights)
Expand All @@ -37,32 +38,35 @@ def gray_scale(self, img):
# Downsamples images too 299 x 299
# converts images to grayscale
img = color.rgb2gray(img).reshape(299, 299, 1)
return (img)


return img


def predict(self,image_dir):##input
def predict(self, image_dir): ##input
##define_image_generator
self.Image_generator = (ImageDataGenerator(preprocessing_function=self.gray_scale, samplewise_std_normalization=True)
.flow_from_directory(image_dir,
target_size=(299, 299),
batch_size=1,
color_mode='rgb',
shuffle=False))
self.Image_generator = ImageDataGenerator(
preprocessing_function=self.gray_scale, samplewise_std_normalization=True
).flow_from_directory(
image_dir,
target_size=(299, 299),
batch_size=1,
color_mode="rgb",
shuffle=False,
)
##reset the image generator to ensure it starts from the first image
self.Image_generator.reset()
##feed images to the model and store the predicted parameters
preds = self.model.predict(self.Image_generator,
steps=self.Image_generator.n // self.Image_generator.batch_size, verbose=1)
preds = self.model.predict(
self.Image_generator,
steps=self.Image_generator.n // self.Image_generator.batch_size,
verbose=1,
)
# convert the parameter values to floating point digits
preds = preds.astype(float)
# define the column names
self.columns = ["ox", "oy", "oz", "ux", "uy", "uz", "vx", "vy", "vz"]
##create a pandas DataFrame of the parameter values
results = pd.DataFrame(preds, columns=self.columns)
##insert the section filenames into the pandas DataFrame
results["Filenames"] = self.Image_generator.filenames[:results.shape[0]]
results["Filenames"] = self.Image_generator.filenames[: results.shape[0]]
ordered_cols = ["Filenames"] + self.columns
self.results = results[ordered_cols] # To get the same column order
self.propagate_angles()
Expand All @@ -71,10 +75,12 @@ def propagate_angles(self):
DV = []
ML = []
for prediction in self.results.iterrows():
m = prediction[1][['ox', 'oy', 'oz', 'ux', 'uy', 'uz', 'vx', 'vy', 'vz']].values.astype(np.float64)
m = prediction[1][
["ox", "oy", "oz", "ux", "uy", "uz", "vx", "vy", "vz"]
].values.astype(np.float64)
cross, k = plane_alignment.find_plane_equation(m)
DV.append(plane_alignment.get_angle(m, cross, k, 'DV'))
ML.append(plane_alignment.get_angle(m, cross, k, 'ML'))
DV.append(plane_alignment.get_angle(m, cross, k, "DV"))
ML.append(plane_alignment.get_angle(m, cross, k, "ML"))
DV = sorted(DV, key=abs)
ML = sorted(ML, key=abs)
len_75 = int(len(ML) * 0.75)
Expand All @@ -84,14 +90,27 @@ def propagate_angles(self):
for section in self.results.iterrows():
section = section[1][self.columns].values
for i in range(4):
section = plane_alignment.Section_adjust(section, mean=DV_mean, direction='DV')
section = plane_alignment.Section_adjust(section, mean=ML_mean, direction='ML')
section = plane_alignment.Section_adjust(
section, mean=DV_mean, direction="DV"
)
section = plane_alignment.Section_adjust(
section, mean=ML_mean, direction="ML"
)

rotated_sections.append(section)
cross, k = plane_alignment.find_plane_equation(section)
print(plane_alignment.get_angle(section, cross, k, 'DV'))
print(plane_alignment.get_angle(section, cross, k, 'ML'))
self.results = rotated_sections
print(plane_alignment.get_angle(section, cross, k, "DV"))
print(plane_alignment.get_angle(section, cross, k, "ML"))

self.results = pd.DataFrame(rotated_sections, columns=self.columns)
##insert the section filenames into the pandas DataFrame
self.results["Filenames"] = self.Image_generator.filenames[
: self.results.shape[0]
]
ordered_cols = ["Filenames"] + self.columns
self.results = self.results[ordered_cols] # To get the same column order

def Save_Results(self, filename):
pd_to_quickNII(results=self.results, orientation='coronal', filename=str(filename))
pd_to_quickNII(
results=self.results, orientation="coronal", filename=str(filename)
)
4 changes: 2 additions & 2 deletions QuickNII_functions.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import pandas as pd
import xml.etree.ElementTree as ET


def pd_to_quickNII(results, orientation='coronal', filename='Download'): ##converts a pandas DataFrame to a quickNII compatible XML
##Get the total number of sections
num_of_sections = results.shape[0]
Expand All @@ -17,13 +16,14 @@ def pd_to_quickNII(results, orientation='coronal', filename='Download'): ##conve
results = results.sort_values('oz')
##Explicitly confirm all filenames are Strings
results['Filenames'] = results['Filenames'].astype(str)
df = results
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, Im going to remove this line and edit future references to df to instead reference results

##for each section append Oxyz, Uxyz and Vxyz parameters to the XML
for i in range(num_of_sections):
child = ET.SubElement(root, 'slice')
child.attrib['filename'] = df.iloc[i,0] ##this is the filename in our results file
root.attrib['name'] = df.iloc[i,0] ##so is this
##Organise our coordinates
ox,oy,oz,ux,uy,uz,vx,vy,vz = results.iloc[i,1:9]
ox,oy,oz,ux,uy,uz,vx,vy,vz = results.iloc[i,1:10]
##these next two values I believe are placeholders required by QuickNII.
child.attrib["height"] = "700"
child.attrib["width"] = "700"
Expand Down
Binary file modified Synthetic_data_final.hdf5
Binary file not shown.