-
Notifications
You must be signed in to change notification settings - Fork 1
/
3DGeneralHough.py
319 lines (228 loc) · 9.26 KB
/
3DGeneralHough.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
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
import os
import numpy as np
import matplotlib.pyplot as plt
from collections import defaultdict
from scipy.misc import imread
from skimage.feature import canny
from scipy.ndimage.filters import sobel
from mpl_toolkits.mplot3d import Axes3D
import cv2 as cv
try:
import cPickle
except ImportError:
import pickle as cPickle
def gradient_orientation(image):
'''
Calculate the gradient orientation for edge point in the image
'''
#scipy.ndimage.sobel
dx = sobel(image, axis=0, mode='constant')
dy = sobel(image, axis=1, mode='constant')
dz = sobel(image, axis=1, mode='constant')
#For 3D instead of a single gradient value, we need two angles that define a normal vector
#Phi is the angle between the positive x-axis to the projection of the normal vector the x-y plane (around +z)
#Psi is the angle between the positive z-axis to the normal vector
phi = np.arctan2(dy ,dx) * 180 / np.pi
psi = np.arctan2(np.sqrt(dx*dx + dy*dy), dz) * 180 / np.pi
print("dx: ", dx.shape)
print("dy: ", dy.shape)
print("phi: ", phi.shape)
print("psi:", psi.shape)
print(np.max(phi))
print(np.min(phi))
print(np.max(psi))
print(np.min(psi))
gradient = np.zeros(image.shape)
return phi, psi
def build_r_table(image, origin):
'''
Build the R-table from the given shape image and a reference point
'''
dx = sobel(image, 0) # x derivative
dy = sobel(image, 1) # y derivative
dz = sobel(image, 2) # z derivativeF
mag = np.sqrt(dx*dx + dy*dy + dz*dz)
mag_norm = mag/np.max(mag)
#mag = generic_gradient_magnitude(image, sobel)
print(dx[0,0,0], dy[0,0,0], dz[0,0,0], mag_norm[0,0,0])
print("dx,dy,dz: ", dx.shape,dy.shape,dz.shape)
#Creating edge array the same size as query image
edges = np.zeros(image.shape, dtype=bool)
print("Edge: ", edges.shape)
for i in range(edges.shape[0]):
for j in range(edges.shape[1]):
for k in range(edges.shape[2]):
if mag_norm[i,j,k] > 0.3 :# and mag_norm[i,j,k] < 0.9:
edges[i,j,k] = True
#Takes (47,40) Edges and calculates the gradients using sobel
phi, psi = gradient_orientation(edges)
print("Phi Dim: ", phi.shape)
r_table = defaultdict(list)
for (i,j,k),value in np.ndenumerate(edges):
if value:
r_table[(int(phi[i,j,k]),int(psi[i,j,k]))].append((origin[0]-i, origin[1]-j, origin[2] - k))
print(r_table.keys())
return r_table
def sobel_edges_3d(grayImage):
dx = sobel(grayImage, 0) # x derivative
dy = sobel(grayImage, 1) # y derivative
dz = sobel(grayImage, 2) # z derivative
#print(dx)
#Get magnitude of gradient
mag = np.sqrt(dx*dx + dy*dy + dz*dz)
mag_norm = mag/np.max(mag)
#Creating edge array the same size as query image
edges = np.zeros(grayImage.shape, dtype=bool)
#print("Edge: ", edges.shape)
for i in range(edges.shape[0]):
for j in range(edges.shape[1]):
for k in range(edges.shape[2]):
if mag_norm[i,j,k] > 0.4 :# and mag_norm[i,j,k] < 0.9:
edges[i,j,k] = True
return edges
def canny_edges_3d(grayImage):
MIN_CANNY_THRESHOLD = 50
MAX_CANNY_THRESHOLD = 100
dim = np.shape(grayImage)
edges_x = np.zeros(grayImage.shape, dtype=bool)
edges_y = np.zeros(grayImage.shape, dtype=bool)
edges_z = np.zeros(grayImage.shape, dtype=bool)
edges = np.zeros(grayImage.shape, dtype=bool)
#print(np.shape(edges))
for i in range(dim[0]):
edges_x[i,:,:] = canny(grayImage[i,:,:], low_threshold=MIN_CANNY_THRESHOLD, high_threshold=MAX_CANNY_THRESHOLD, sigma = 0)
for j in range(dim[1]):
edges_y[:,j,:] = canny(grayImage[:,j,:], low_threshold=MIN_CANNY_THRESHOLD, high_threshold=MAX_CANNY_THRESHOLD, sigma = 0)
for k in range(dim[2]):
edges_z[:,:,k] = canny(grayImage[:,:,k], low_threshold=MIN_CANNY_THRESHOLD, high_threshold=MAX_CANNY_THRESHOLD, sigma = 0)
# edges = canny(grayImage, low_threshold=MIN_CANNY_THRESHOLD, high_threshold=MAX_CANNY_THRESHOLD)
for i in range(dim[0]):
for j in range(dim[1]):
for k in range(dim[2]):
edges[i,j,k] = (edges_x[i,j,k] and edges_y[i,j,k]) or (edges_x[i,j,k] and edges_z[i,j,k]) or (edges_y[i,j,k] and edges_z[i,j,k])
#edges[i,j,k] = (edges_x[i,j,k]) or (edges_y[i,j,k]) or (edges_z[i,j,k])
return edges
def LoG_3d(grayImage):
#https://stackoverflow.com/questions/22050199/python-implementation-of-the-laplacian-of-gaussian-edge-detection
return 0
def accumulate_gradients(r_table, grayImage):
'''
Perform a General Hough Transform with the given image and R-table
'''
#Choose Edge Detector as desired
#edges = canny_edges_3d(grayImage)
edges = sobel_edges_3d(grayImage)
phi, psi = gradient_orientation(edges)
accumulator = np.zeros(grayImage.shape)
print("Accumulator shape: ", accumulator.shape)
#print(accumulator)
#print(edges)
print("Start Accumulation")
for (i,j,k),value in np.ndenumerate(edges):
#print(i,j,k,value)
if value:
#print(r_table.keys())
#Changed to int(gradient) which makes more sense
for r in r_table[(int(phi[i,j,k]), int(psi[i,j,k]))]:
accum_i, accum_j, accum_k = i+r[0], j+r[1], k+r[2]
if accum_i < accumulator.shape[0] and accum_j < accumulator.shape[1] and accum_k < accumulator.shape[2]:
accumulator[int(accum_i), int(accum_j), int(accum_k)] += 1
#print(i,j)
return accumulator
def general_hough_closure(reference_image):
'''
Generator function to create a closure with the reference image and origin
at the center of the reference image
Returns a function f, which takes a query image and returns the accumulator
'''
print(reference_image.shape)
referencePoint = (reference_image.shape[0]/2, reference_image.shape[1]/2, reference_image.shape[2]/2)
print(referencePoint)
r_table = build_r_table(reference_image, referencePoint)
def f(query_image):
return accumulate_gradients(r_table, query_image)
print("Finish General Hough Closure Function")
return f
def n_max(a, n):
'''
Return the N max elements and indices in a
'''
indices = a.ravel().argsort()[-n:]
indices = (np.unravel_index(i, a.shape) for i in indices)
return [(a[i], i) for i in indices]
def test_general_hough(gh, reference_image, query):
'''
Uses a GH closure to detect shapes in an image and create nice output
'''
#query_image = imread(query, flatten=True)
query_image = query
accumulator = gh(query_image)
print("Accumulator Size: ", accumulator.shape)
#plt.clf() #Clear the Current Figure
#plt.gray() #Set colormap to gray
fig = plt.figure()
plt.gray()
fig.add_subplot(2,2,1)
plt.title('Reference image')
plt.imshow(reference_image[:,:,5])
fig.add_subplot(2,2,2)
plt.title('Query image')
plt.imshow(query_image[:,:,25])
fig.add_subplot(2,2,3)
plt.title('Accumulator')
plt.imshow(accumulator[:,:,25])
fig.add_subplot(2,2,4)
plt.title('Detection')
plt.imshow(query_image[:,:,25])
plt.show()
# top 5 results in red
m = n_max(accumulator, 15)
print(m)
x_points = [pt[1][0] for pt in m]
y_points = [pt[1][1] for pt in m]
z_points = [pt[1][2] for pt in m]
print(x_points)
print(y_points)
print(z_points)
plt.scatter(y_points, x_points, marker='o', color='r')
return
def test():
dicom_downsized = cPickle.load(open("dicom_3d_9183761_dwn4x.pkl","rb"),encoding = 'latin1')
print(np.shape(dicom_downsized))
c12_vertebrae = cPickle.load(open("dicom_3d_9183761_sample.pkl","rb"),encoding = 'latin1')
print(np.shape(c12_vertebrae))
detect_s = general_hough_closure(c12_vertebrae)
test_general_hough(detect_s, c12_vertebrae, dicom_downsized[:,30:90,:])
#test_general_hough(detect_s, c12_vertebrae, c12_vertebrae)
'''
#Testing with 3D Images
#Testing with a hollow cube
dicom_3d = np.zeros((40,40,40))
#Make both YZ planes have white sides
dicom_3d[10:15,10:30,10:30] = 127
dicom_3d[25:30,10:30,10:30] = 127
#XZ Planes
dicom_3d[10:30,10:15,10:30] = 127
dicom_3d[10:30,25:30,10:30] = 127
#XY Planes
dicom_3d[10:30,10:30,10:15] = 127
dicom_3d[10:30,10:30,25:30] = 127
print(np.shape(dicom_3d))
#print(dicom_3d[3,3,4])
#Creating a test image
test_3d = np.zeros((40,40,80))
test_3d[0:40,0:40,25:45] = dicom_3d[0:40,0:40,10:30]
test_3d[13:27,13:27,28:42] = 0
test_3d[2:22,10:30,2:22] = 170
test_3d[6:18,14:26,6:18] = 0
#fig = plt.figure()
#fig.add_subplot(1,2,1)
#plt.imshow(dicom_3d[:,:,20])
#fig.add_subplot(1,2,2)
#plt.imshow(test_3d[:,:,20])
#plt.show()
'''
if __name__ == '__main__':
print(os.getcwd())
#os.chdir('C:\\Users\\yoons\\Documents\\4th Year Semester 1\\ESC499 - Thesis\\Undergraduate Thesis Scripts')
test()