In [1]:
import sys
sys.path.append('../code/functions')
import cv2
import pickle
from connectLib import otsuVox
from connectLib import clusterThresh
from plosLib import pipeline as PLOS
from random import randrange as rand
from cluster import Cluster
import numpy as np
import matplotlib.pyplot as plt
In [2]:
def neighborhoodDensity(data, interPlane = 1, intraPlane = 1, percentile = 50):
output = np.zeros_like(data)
for z in range(data.shape[0]):
for y in range(data.shape[1]):
for x in range(data.shape[2]):
zLow = z-intraPlane
zHigh = z+intraPlane
yLow = y-interPlane
yHigh = y+interPlane
xLow = x-interPlane
xHigh = x+interPlane
if zLow>=0 and zHigh<data.shape[0] and yLow>=0 and yHigh<data.shape[1] and xLow>=0 and xHigh<data.shape[2]:
subVol = data[zLow:zHigh, yLow:yHigh, xLow:xHigh]
if not all(subVol.shape) == 0:
thresh = np.percentile(subVol, percentile)
binSubVol = subVol >= thresh
output[z][y][x] = (np.count_nonzero(binSubVol)/float(interPlane*interPlane*intraPlane)) * data[z][y][x] * np.average(subVol)
return output
In [3]:
def generatePointSet():
center = (rand(0, 9), rand(0, 999), rand(0, 999))
toPopulate = []
for z in range(-3, 2):
for y in range(-3, 2):
for x in range(-3, 2):
curPoint = (center[0]+z, center[1]+y, center[2]+x)
#only populate valid points
valid = True
for dim in range(3):
if curPoint[dim] < 0 or curPoint[dim] >= 1000:
valid = False
if valid:
toPopulate.append(curPoint)
return set(toPopulate)
def generateTestVolume():
#create a test volume
volume = np.zeros((10, 1000, 1000))
myPointSet = set()
for _ in range(rand(1000, 2000)):
potentialPointSet = generatePointSet()
#be sure there is no overlap
while len(myPointSet.intersection(potentialPointSet)) > 0:
potentialPointSet = generatePointSet()
for elem in potentialPointSet:
myPointSet.add(elem)
#populate the true volume
for elem in myPointSet:
volume[elem[0], elem[1], elem[2]] = rand(40000, 60000)
#introduce noise
noiseVolume = np.copy(volume)
for z in range(noiseVolume.shape[0]):
for y in range(noiseVolume.shape[1]):
for x in range(noiseVolume.shape[2]):
if not (z, y, x) in myPointSet:
toPop = rand(0, 10)
if toPop == 5:
noiseVolume[z][y][x] = rand(0, 60000)
return volume, noiseVolume
def generateDenseVolume(n):
#create a test volume
volume = np.zeros((10, 1000, 1000))
myPointSet = set()
for _ in range(n):
potentialPointSet = generatePointSet()
#be sure there is no overlap
while len(myPointSet.intersection(potentialPointSet)) > 0:
potentialPointSet = generatePointSet()
for elem in potentialPointSet:
myPointSet.add(elem)
#populate the true volume
for elem in myPointSet:
volume[elem[0], elem[1], elem[2]] = rand(40000, 60000)
#introduce noise
noiseVolume = np.copy(volume)
for z in range(noiseVolume.shape[0]):
for y in range(noiseVolume.shape[1]):
for x in range(noiseVolume.shape[2]):
if not (z, y, x) in myPointSet:
toPop = rand(0, 10)
if toPop == 5:
noiseVolume[z][y][x] = rand(0, 60000)
return volume, noiseVolume
In [4]:
def f1score(trueClusterList, testClusterList):
tp = 0
fp = 0
fn = 0
testClusterTuples = []
for elem in testClusterList:
myTupleList = []
members = elem.members
for member in members:
myTupleList.append(tuple(member))
testClusterTuples.append(myTupleList)
trueClusterTuples = []
for elem in trueClusterList:
myTupleList = []
members = elem.members
for member in members:
myTupleList.append(tuple(member))
trueClusterTuples.append(myTupleList)
truePositives = []
for testList in testClusterTuples:
found = False
for trueList in trueClusterTuples:
if len(set(testList).intersection(set(trueList))) > 0:
found = True
if found:
truePositives.append(testList)
tp+=1
fp = len(testClusterList) - tp
fn = len(trueClusterList) - tp
precision = float(tp)/float(fp+tp)
recall = float(tp)/float(tp+fn)
f1 = (2*precision*recall)/(precision+recall)
return precision, recall, f1, truePositives, trueClusterTuples, testClusterTuples
In [5]:
def applyGradient(volume, originX, originY):
outStack = []
maxDistance = np.sqrt((volume[0].shape[0])**2+(volume[0].shape[1])**2)
for sample in volume:
outSample = np.zeros_like(sample)
for y in range(sample.shape[0]):
for x in range(sample.shape[1]):
distance = np.sqrt((x - originX)**2+(y - originY)**2)
sigma = np.sqrt(distance)/np.sqrt(maxDistance)
modifier = 1.-(sigma * distance/maxDistance)
outSample[y][x] = modifier * sample[y][x]
outStack.append(outSample)
return np.stack(outStack)
In [22]:
#running test on wills version of thresholding, maybe there is a way to either boost his implementation or combine it with mine to form a better filter
testGenVolLabel, testGenVol = generateTestVolume()
In [23]:
plt.figure()
plt.title('Non-Gradient Volume at z=5')
plt.imshow(testGenVol[5], cmap='gray')
plt.show()
In [32]:
testGenVolGrad = applyGradient(testGenVol, 0, 0)
In [33]:
plt.figure()
plt.title('Gradient Volume at z=5')
plt.imshow(testGenVolGrad[5], cmap='gray')
plt.show()
In [6]:
statListG = []
statListN = []
def executeGradSim():
testVol, noiseVol = generateTestVolume()
gradVol = applyGradient(noiseVol, rand(0, noiseVol[0].shape[0]), rand(0, noiseVol[0].shape[1]))
realSimN = neighborhoodDensity(noiseVol, 2, 2, 50)
realSimNB = otsuVox(realSimN)
realSimG = neighborhoodDensity(gradVol, 2, 2, 50)
realSimGB = otsuVox(realSimG)
clustersN = clusterThresh(realSimNB[4:6])
clustersG = clusterThresh(realSimGB[4:6])
clustersT = clusterThresh(testVol[4:6])
precisionN, recallN, f1N, _, _, _ = f1score(clustersT, clustersN)
precisionG, recallG, f1G, _, _, _ = f1score(clustersT, clustersG)
print 'Non-Gradient:'
print '\tPrecision: ', precisionN
print '\tRecall: ', recallN
print '\tf1: ', f1N
print 'Gradient:'
print '\tPrecision: ', precisionG
print '\tRecall: ', recallG
print '\tf1: ', f1G
statListN.append([precisionN, recallN, f1N])
statListG.append([precisionG, recallG, f1G])
In [41]:
executeGradSim()
In [44]:
testGenVolLabel, testGenVol = generateTestVolume()
In [45]:
plt.figure()
plt.title('Non-Dense Volume at z=5')
plt.imshow(testGenVol[5], cmap='gray')
plt.show()
In [52]:
denseTestVol, denseNoiseVol = generateDenseVolume()
In [53]:
plt.figure()
plt.title('Dense Volume at z=5')
plt.imshow(denseNoiseVol[5], cmap='gray')
plt.show()
In [7]:
statListG = []
statListN = []
def executeDenseSim(n):
testVol, noiseVol = generateTestVolume()
denseTestVol, denseNoiseVol = generateDenseVolume(n)
realSimN = neighborhoodDensity(noiseVol, 2, 2, 50)
realSimNB = otsuVox(realSimN)
realSimD = neighborhoodDensity(denseNoiseVol, 2, 2, 50)
realSimDB = otsuVox(realSimD)
clustersN = clusterThresh(realSimNB[4:6])
clustersD = clusterThresh(realSimDB[4:6])
clustersNT = clusterThresh(testVol[4:6])
clustersDT = clusterThresh(denseTestVol[4:6])
precisionN, recallN, f1N, _, _, _ = f1score(clustersNT, clustersN)
precisionG, recallG, f1G, _, _, _ = f1score(clustersDT, clustersD)
print 'Non-Dense:'
print '\tPrecision: ', precisionN
print '\tRecall: ', recallN
print '\tf1: ', f1N
print 'Dense:'
print '\tPrecision: ', precisionG
print '\tRecall: ', recallG
for i in range(5):
print '\tf1: ', f1G
statListN.append([precisionN, recallN, f1N])
statListG.append([precisionG, recallG, f1G])
return noiseVol, denseNoiseVol
In [65]:
nV, dnV = executeDenseSim(15000)
In [66]:
nV, dnV = executeDenseSim(25000)
In [8]:
def binaryThreshold(img, percentile=90):
img = (img/256).astype('uint8')
threshImg = np.zeros_like(img)
percentile = np.percentile(img, percentile)
for i in range(len(img)):
threshImg[i] = cv2.threshold(img[i], percentile, 255, cv2.THRESH_BINARY)[1]
return threshImg
In [9]:
def adaptiveThreshold(inImg, sx, sy, sz, p):
outImg = np.zeros_like(inImg)
shape = outImg.shape
subXLen = shape[0]/sx
subYLen = shape[1]/sy
subZLen = shape[2]/sz
for xInc in range(1, sx + 1):
for yInc in range(1, sy + 1):
for zInc in range(1, sz + 1):
sub = inImg[(xInc-1)*subXLen: xInc*subXLen, (yInc-1)*subYLen: yInc*subYLen, (zInc-1)*subZLen: zInc*subZLen]
subThresh = binaryThreshold(sub, p)
outImg[(xInc-1)*subXLen: xInc*subXLen, (yInc-1)*subYLen: yInc*subYLen, (zInc-1)*subZLen: zInc*subZLen] = subThresh
return outImg
Testing the same sims using will algorithm. Maybe there is a way to boost it or combine both mine and wills in order to create a stronger overall pipeline
In [14]:
testVol, noiseVol = generateTestVolume()
noiseVolGrad = applyGradient(testVol, 0, 0)
testVolDense, noiseVolDense = generateDenseVolume(15000)
testAdaptive = adaptiveThreshold(noiseVol, 9, 9, 9, 95)
testGrad = adaptiveThreshold(noiseVolGrad, 9, 9, 9, 95)
testDense = adaptiveThreshold(noiseVolDense, 9, 9, 9, 95)
In [15]:
clustersA = clusterThresh(testAdaptive[4:6])
clustersG = clusterThresh(testGrad[4:6])
clustersD = clusterThresh(testDense[4:6])
clustersT1 = clusterThresh(testVol[4:6])
clustersT2 = clusterThresh(testVolDense[4:6])
precisionA, recallA, f1A, _, _, _ = f1score(clustersT1, clustersA)
precisionG, recallG, f1G, _, _, _ = f1score(clustersT1, clustersG)
precisionD, recallD, f1D, _, _, _ = f1score(clustersT2, clustersD)
print 'Base:'
print '\tPrecision: ', precisionA
print '\tRecall: ', recallA
print '\tf1: ', f1A
print 'Gradient:'
print '\tPrecision: ', precisionG
print '\tRecall: ', recallG
print '\tf1: ', f1G
print 'Dense:'
print '\tPrecision: ', precisionD
print '\tRecall: ', recallD
print '\tf1: ', f1D
In [17]:
statsSA = []
statsSG = []
statsSD = []
for i in range(5):
testVol, noiseVol = generateTestVolume()
noiseVolGrad = applyGradient(testVol, 0, 0)
testVolDense, noiseVolDense = generateDenseVolume(15000)
testAdaptive = adaptiveThreshold(noiseVol, 9, 9, 9, 95)
testGrad = adaptiveThreshold(noiseVolGrad, 9, 9, 9, 95)
testDense = adaptiveThreshold(noiseVolDense, 9, 9, 9, 95)
clustersA = clusterThresh(testAdaptive[4:6])
clustersG = clusterThresh(testGrad[4:6])
clustersD = clusterThresh(testDense[4:6])
clustersT1 = clusterThresh(testVol[4:6])
clustersT2 = clusterThresh(testVolDense[4:6])
precisionA, recallA, f1A, _, _, _ = f1score(clustersT1, clustersA)
precisionG, recallG, f1G, _, _, _ = f1score(clustersT1, clustersG)
precisionD, recallD, f1D, _, _, _ = f1score(clustersT2, clustersD)
statsA.append([precisionA, recallA, f1A])
statsG.append([precisionG, recallG, f1G])
statsD.append([precisionD, recallD, f1D])
print 'Base:'
print '\tPrecision: ', precisionA
print '\tRecall: ', recallA
print '\tf1: ', f1A
print 'Gradient:'
print '\tPrecision: ', precisionG
print '\tRecall: ', recallG
print '\tf1: ', f1G
print 'Dense:'
print '\tPrecision: ', precisionD
print '\tRecall: ', recallD
print '\tf1: ', f1D
In [22]:
plt.figure()
plt.title('Precision vs Trial, R=Base, B=Gradient, G=Dense')
pA = [elem[0] for elem in statsA]
pG = [elem[0] for elem in statsG]
pD = [elem[0] for elem in statsD]
plt.scatter(range(5), pA, c='r')
plt.scatter(range(5), pG, c='b')
plt.scatter(range(5), pD, c='g')
plt.show()
In [23]:
plt.figure()
plt.title('Recall vs Trial, R=Base, B=Gradient, G=Dense')
pA = [elem[1] for elem in statsA]
pG = [elem[1] for elem in statsG]
pD = [elem[1] for elem in statsD]
plt.scatter(range(5), pA, c='r')
plt.scatter(range(5), pG, c='b')
plt.scatter(range(5), pD, c='g')
plt.show()
In [24]:
plt.figure()
plt.title('F1 vs Trial, R=Base, B=Gradient, G=Dense')
pA = [elem[2] for elem in statsA]
pG = [elem[2] for elem in statsG]
pD = [elem[2] for elem in statsD]
plt.scatter(range(5), pA, c='r')
plt.scatter(range(5), pG, c='b')
plt.scatter(range(5), pD, c='g')
plt.show()
These performance metrics are not perfect, but they are promising. Below I attempt to boost the algorithm in a couple of ways to increase performance
In [10]:
def boostOverParam(volumeChain, n=2):
outVol = np.zeros_like(volumeChain[0])
for z in range(volumeChain[0].shape[0]):
for y in range(volumeChain[0].shape[1]):
for x in range(volumeChain[0].shape[2]):
count = 0.
for elem in volumeChain:
if elem[z][y][x] > 0:
count+=1.
if count > n:
outVol[z][y][x] = np.sum([elem[z][y][x] for elem in volumeChain])/float(count)
return outVol
In [11]:
testVol, noiseVol = generateTestVolume()
noiseVolGrad = applyGradient(testVol, 0, 0)
testVolDense, noiseVolDense = generateDenseVolume(15000)
testAdaptive = []
testGrad = []
testDense = []
for i in range(3, 9):
testAdaptive.append(adaptiveThreshold(noiseVol, i, i, i, 95))
testGrad.append(adaptiveThreshold(noiseVolGrad, i, i, i, 95))
testDense.append(adaptiveThreshold(noiseVolDense, i, i, i, 95))
In [31]:
outVolA = boostOverParam(testAdaptive)
outVolG = boostOverParam(testGrad)
outVolD = boostOverParam(testDense)
In [34]:
clustersAB = clusterThresh(outVolA[4:6])
clustersGB = clusterThresh(outVolG[4:6])
clustersDB = clusterThresh(outVolD[4:6])
clustersT1B = clusterThresh(testVol[4:6])
clustersT2B = clusterThresh(testVolDense[4:6])
precisionAB, recallAB, f1AB, _, _, _ = f1score(clustersT1B, clustersAB)
precisionGB, recallGB, f1GB, _, _, _ = f1score(clustersT1B, clustersGB)
precisionDB, recallDB, f1DB, _, _, _ = f1score(clustersT2B, clustersDB)
print 'Base:'
print '\tPrecision: ', precisionAB
print '\tRecall: ', recallAB
print '\tf1: ', f1AB
print 'Gradient:'
print '\tPrecision: ', precisionGB
print '\tRecall: ', recallGB
print '\tf1: ', f1GB
print 'Dense:'
print '\tPrecision: ', precisionDB
print '\tRecall: ', recallDB
print '\tf1: ', f1DB
In [37]:
outVolA = boostOverParam(testAdaptive, 5)
outVolG = boostOverParam(testGrad, 5)
outVolD = boostOverParam(testDense, 5)
clustersAB = clusterThresh(outVolA[4:6])
clustersGB = clusterThresh(outVolG[4:6])
clustersDB = clusterThresh(outVolD[4:6])
clustersT1B = clusterThresh(testVol[4:6])
clustersT2B = clusterThresh(testVolDense[4:6])
precisionAB, recallAB, f1AB, _, _, _ = f1score(clustersT1B, clustersAB)
precisionGB, recallGB, f1GB, _, _, _ = f1score(clustersT1B, clustersGB)
precisionDB, recallDB, f1DB, _, _, _ = f1score(clustersT2B, clustersDB)
print 'Base:'
print '\tPrecision: ', precisionAB
print '\tRecall: ', recallAB
print '\tf1: ', f1AB
print 'Gradient:'
print '\tPrecision: ', precisionGB
print '\tRecall: ', recallGB
print '\tf1: ', f1GB
print 'Dense:'
print '\tPrecision: ', precisionDB
print '\tRecall: ', recallDB
print '\tf1: ', f1DB
In [17]:
outVolA = boostOverParam(testAdaptive, 5)
outVolG = boostOverParam(testGrad, 5)
outVolD = boostOverParam(testDense, 5)
multVolA = outVolA > 0
multVolG = outVolG > 0
multVolD = outVolD > 0
clusterVolA = neighborhoodDensity(np.multiply(noiseVol, multVolA), 2, 2, 50)
clusterVolG = neighborhoodDensity(np.multiply(noiseVolGrad, multVolG), 2, 2, 50)
clusterVolD = neighborhoodDensity(np.multiply(noiseVolDense, multVolD), 2, 2, 50)
clustersAB = clusterThresh(clusterVolA[4:6])
clustersGB = clusterThresh(clusterVolG[4:6])
clustersDB = clusterThresh(clusterVolD[4:6])
clustersT1B = clusterThresh(testVol[4:6])
clustersT2B = clusterThresh(testVolDense[4:6])
precisionAB, recallAB, f1AB, _, _, _ = f1score(clustersT1B, clustersAB)
precisionGB, recallGB, f1GB, _, _, _ = f1score(clustersT1B, clustersGB)
precisionDB, recallDB, f1DB, _, _, _ = f1score(clustersT2B, clustersDB)
print 'Base:'
print '\tPrecision: ', precisionAB
print '\tRecall: ', recallAB
print '\tf1: ', f1AB
print 'Gradient:'
print '\tPrecision: ', precisionGB
print '\tRecall: ', recallGB
print '\tf1: ', f1GB
print 'Dense:'
print '\tPrecision: ', precisionDB
print '\tRecall: ', recallDB
print '\tf1: ', f1DB
In [19]:
outVolA = neighborhoodDensity(testAdaptive[-1], 2, 2, 50)
outVolG = neighborhoodDensity(testGrad[-1], 2, 2, 50)
outVolD = neighborhoodDensity(testDense[-1], 2, 2, 50)
multVolA = otsuVox(outVolA)
multVolG = otsuVox(outVolG)
multVolD = otsuVox(outVolD)
clusterVolA = adaptiveThreshold(np.multiply(noiseVol, multVolA), 9, 9, 9, 95)
clusterVolG = adaptiveThreshold(np.multiply(noiseVolGrad, multVolG), 9, 9, 9, 95)
clusterVolD = adaptiveThreshold(np.multiply(noiseVolDense, multVolD), 9, 9, 9, 95)
clustersAB = clusterThresh(clusterVolA[4:6])
clustersGB = clusterThresh(clusterVolG[4:6])
clustersDB = clusterThresh(clusterVolD[4:6])
clustersT1B = clusterThresh(testVol[4:6])
clustersT2B = clusterThresh(testVolDense[4:6])
precisionAB, recallAB, f1AB, _, _, _ = f1score(clustersT1B, clustersAB)
precisionGB, recallGB, f1GB, _, _, _ = f1score(clustersT1B, clustersGB)
precisionDB, recallDB, f1DB, _, _, _ = f1score(clustersT2B, clustersDB)
print 'Base:'
print '\tPrecision: ', precisionAB
print '\tRecall: ', recallAB
print '\tf1: ', f1AB
print 'Gradient:'
print '\tPrecision: ', precisionGB
print '\tRecall: ', recallGB
print '\tf1: ', f1GB
print 'Dense:'
print '\tPrecision: ', precisionDB
print '\tRecall: ', recallDB
print '\tf1: ', f1DB
In [ ]:
statsA = []
statsG = []
statsD = []
for i in range(3):
testVol, noiseVol = generateTestVolume()
noiseVolGrad = applyGradient(testVol, 0, 0)
testVolDense, noiseVolDense = generateDenseVolume(15000)
outVolA = neighborhoodDensity(noiseVol, 2, 2, 50)
outVolG = neighborhoodDensity(noiseVolGrad, 2, 2, 50)
outVolD = neighborhoodDensity(noiseVolDense, 2, 2, 50)
multVolA = otsuVox(outVolA)
multVolG = otsuVox(outVolG)
multVolD = otsuVox(outVolD)
clusterVolA = adaptiveThreshold(np.multiply(noiseVol, multVolA), 9, 9, 9, 95)
clusterVolG = adaptiveThreshold(np.multiply(noiseVolGrad, multVolG), 9, 9, 9, 95)
clusterVolD = adaptiveThreshold(np.multiply(noiseVolDense, multVolD), 9, 9, 9, 95)
clustersAB = clusterThresh(clusterVolA[4:6])
clustersGB = clusterThresh(clusterVolG[4:6])
clustersDB = clusterThresh(clusterVolD[4:6])
clustersT1B = clusterThresh(testVol[4:6])
clustersT2B = clusterThresh(testVolDense[4:6])
precisionAB, recallAB, f1AB, _, _, _ = f1score(clustersT1B, clustersAB)
precisionGB, recallGB, f1GB, _, _, _ = f1score(clustersT1B, clustersGB)
precisionDB, recallDB, f1DB, _, _, _ = f1score(clustersT2B, clustersDB)
statsA.append([precisionAB, recallAB, f1AB])
statsG.append([precisionGB, recallGB, f1GB])
statsD.append([precisionDB, recallDB, f1DB])
print 'Base:'
print '\tPrecision: ', precisionAB
print '\tRecall: ', recallAB
print '\tf1: ', f1AB
print 'Gradient:'
print '\tPrecision: ', precisionGB
print '\tRecall: ', recallGB
print '\tf1: ', f1GB
print 'Dense:'
print '\tPrecision: ', precisionDB
print '\tRecall: ', recallDB
print '\tf1: ', f1DB
In [ ]: