Commit 18c2bcddd4fbb36ebbef13006c804f4ce661476a

Authored by Thiago Franco de Moraes
1 parent 73ddbb08
Exists in master

Moved all cython codes to invesalius_cy

invesalius/data/cy_mesh.pyx
@@ -1,466 +0,0 @@ @@ -1,466 +0,0 @@
1 -# distutils: language = c++  
2 -#cython: boundscheck=False  
3 -#cython: wraparound=False  
4 -#cython: initializedcheck=False  
5 -#cython: cdivision=True  
6 -#cython: nonecheck=False  
7 -  
8 -import sys  
9 -import time  
10 -cimport numpy as np  
11 -  
12 -from libc.math cimport sin, cos, acos, exp, sqrt, fabs, M_PI  
13 -from libc.stdlib cimport abs as cabs  
14 -from cython.operator cimport dereference as deref, preincrement as inc  
15 -from libcpp.map cimport map  
16 -from libcpp.unordered_map cimport unordered_map  
17 -from libcpp.set cimport set  
18 -from libcpp.vector cimport vector  
19 -from libcpp.pair cimport pair  
20 -from libcpp cimport bool  
21 -from libcpp.deque cimport deque as cdeque  
22 -from cython.parallel import prange  
23 -  
24 -from cy_my_types cimport vertex_t, normal_t, vertex_id_t  
25 -  
26 -import numpy as np  
27 -import vtk  
28 -  
29 -from vtk.util import numpy_support  
30 -  
31 -ctypedef float weight_t  
32 -  
33 -cdef struct Point:  
34 - vertex_t x  
35 - vertex_t y  
36 - vertex_t z  
37 -  
38 -ctypedef pair[vertex_id_t, vertex_id_t] key  
39 -  
40 -  
41 -cdef class Mesh:  
42 - cdef vertex_t[:, :] vertices  
43 - cdef vertex_id_t[:, :] faces  
44 - cdef normal_t[:, :] normals  
45 -  
46 - cdef unordered_map[int, vector[vertex_id_t]] map_vface  
47 - cdef unordered_map[vertex_id_t, int] border_vertices  
48 -  
49 - cdef bool _initialized  
50 -  
51 - def __cinit__(self, pd=None, other=None):  
52 - cdef int i  
53 - cdef map[key, int] edge_nfaces  
54 - cdef map[key, int].iterator it  
55 - if pd:  
56 - self._initialized = True  
57 - _vertices = numpy_support.vtk_to_numpy(pd.GetPoints().GetData())  
58 - _vertices.shape = -1, 3  
59 -  
60 - _faces = numpy_support.vtk_to_numpy(pd.GetPolys().GetData())  
61 - _faces.shape = -1, 4  
62 -  
63 - _normals = numpy_support.vtk_to_numpy(pd.GetCellData().GetArray("Normals"))  
64 - _normals.shape = -1, 3  
65 -  
66 - self.vertices = _vertices  
67 - self.faces = _faces  
68 - self.normals = _normals  
69 -  
70 - for i in xrange(_faces.shape[0]):  
71 - self.map_vface[self.faces[i, 1]].push_back(i)  
72 - self.map_vface[self.faces[i, 2]].push_back(i)  
73 - self.map_vface[self.faces[i, 3]].push_back(i)  
74 -  
75 - edge_nfaces[key(min(self.faces[i, 1], self.faces[i, 2]), max(self.faces[i, 1], self.faces[i, 2]))] += 1  
76 - edge_nfaces[key(min(self.faces[i, 2], self.faces[i, 3]), max(self.faces[i, 2], self.faces[i, 3]))] += 1  
77 - edge_nfaces[key(min(self.faces[i, 1], self.faces[i, 3]), max(self.faces[i, 1], self.faces[i, 3]))] += 1  
78 -  
79 - it = edge_nfaces.begin()  
80 -  
81 - while it != edge_nfaces.end():  
82 - if deref(it).second == 1:  
83 - self.border_vertices[deref(it).first.first] = 1  
84 - self.border_vertices[deref(it).first.second] = 1  
85 -  
86 - inc(it)  
87 -  
88 - elif other:  
89 - _other = <Mesh>other  
90 - self._initialized = True  
91 - self.vertices = _other.vertices.copy()  
92 - self.faces = _other.faces.copy()  
93 - self.normals = _other.normals.copy()  
94 - self.map_vface = unordered_map[int, vector[vertex_id_t]](_other.map_vface)  
95 - self.border_vertices = unordered_map[vertex_id_t, int](_other.border_vertices)  
96 - else:  
97 - self._initialized = False  
98 -  
99 - cdef void copy_to(self, Mesh other):  
100 - """  
101 - Copies self content to other.  
102 - """  
103 - if self._initialized:  
104 - other.vertices[:] = self.vertices  
105 - other.faces[:] = self.faces  
106 - other.normals[:] = self.normals  
107 - other.map_vface = unordered_map[int, vector[vertex_id_t]](self.map_vface)  
108 - other.border_vertices = unordered_map[vertex_id_t, int](self.border_vertices)  
109 - else:  
110 - other.vertices = self.vertices.copy()  
111 - other.faces = self.faces.copy()  
112 - other.normals = self.normals.copy()  
113 -  
114 - other.map_vface = self.map_vface  
115 - other.border_vertices = self.border_vertices  
116 -  
117 - def to_vtk(self):  
118 - """  
119 - Converts Mesh to vtkPolyData.  
120 - """  
121 - vertices = np.asarray(self.vertices)  
122 - faces = np.asarray(self.faces)  
123 - normals = np.asarray(self.normals)  
124 -  
125 - points = vtk.vtkPoints()  
126 - points.SetData(numpy_support.numpy_to_vtk(vertices))  
127 -  
128 - id_triangles = numpy_support.numpy_to_vtkIdTypeArray(faces)  
129 - triangles = vtk.vtkCellArray()  
130 - triangles.SetCells(faces.shape[0], id_triangles)  
131 -  
132 - pd = vtk.vtkPolyData()  
133 - pd.SetPoints(points)  
134 - pd.SetPolys(triangles)  
135 -  
136 - return pd  
137 -  
138 - cdef vector[vertex_id_t]* get_faces_by_vertex(self, int v_id) nogil:  
139 - """  
140 - Returns the faces whose vertex `v_id' is part.  
141 - """  
142 - return &self.map_vface[v_id]  
143 -  
144 - cdef set[vertex_id_t]* get_ring1(self, vertex_id_t v_id) nogil:  
145 - """  
146 - Returns the ring1 of vertex `v_id'  
147 - """  
148 - cdef vertex_id_t f_id  
149 - cdef set[vertex_id_t]* ring1 = new set[vertex_id_t]()  
150 - cdef vector[vertex_id_t].iterator it = self.map_vface[v_id].begin()  
151 -  
152 - while it != self.map_vface[v_id].end():  
153 - f_id = deref(it)  
154 - inc(it)  
155 - if self.faces[f_id, 1] != v_id:  
156 - ring1.insert(self.faces[f_id, 1])  
157 - if self.faces[f_id, 2] != v_id:  
158 - ring1.insert(self.faces[f_id, 2])  
159 - if self.faces[f_id, 3] != v_id:  
160 - ring1.insert(self.faces[f_id, 3])  
161 -  
162 - return ring1  
163 -  
164 - cdef bool is_border(self, vertex_id_t v_id) nogil:  
165 - """  
166 - Check if vertex `v_id' is a vertex border.  
167 - """  
168 - return self.border_vertices.find(v_id) != self.border_vertices.end()  
169 -  
170 - cdef vector[vertex_id_t]* get_near_vertices_to_v(self, vertex_id_t v_id, float dmax) nogil:  
171 - """  
172 - Returns all vertices with distance at most `d' to the vertex `v_id'  
173 -  
174 - Params:  
175 - v_id: id of the vertex  
176 - dmax: the maximum distance.  
177 - """  
178 - cdef vector[vertex_id_t]* idfaces  
179 - cdef vector[vertex_id_t]* near_vertices = new vector[vertex_id_t]()  
180 -  
181 - cdef cdeque[vertex_id_t] to_visit  
182 - cdef unordered_map[vertex_id_t, bool] status_v  
183 - cdef unordered_map[vertex_id_t, bool] status_f  
184 -  
185 - cdef vertex_t *vip  
186 - cdef vertex_t *vjp  
187 -  
188 - cdef float distance  
189 - cdef int nf, nid, j  
190 - cdef vertex_id_t f_id, vj  
191 -  
192 - vip = &self.vertices[v_id, 0]  
193 - to_visit.push_back(v_id)  
194 - while(not to_visit.empty()):  
195 - v_id = to_visit.front()  
196 - to_visit.pop_front()  
197 -  
198 - status_v[v_id] = True  
199 -  
200 - idfaces = self.get_faces_by_vertex(v_id)  
201 - nf = idfaces.size()  
202 -  
203 - for nid in xrange(nf):  
204 - f_id = deref(idfaces)[nid]  
205 - if status_f.find(f_id) == status_f.end():  
206 - status_f[f_id] = True  
207 -  
208 - for j in xrange(3):  
209 - vj = self.faces[f_id, j+1]  
210 - if status_v.find(vj) == status_v.end():  
211 - status_v[vj] = True  
212 - vjp = &self.vertices[vj, 0]  
213 - distance = sqrt((vip[0] - vjp[0]) * (vip[0] - vjp[0]) \  
214 - + (vip[1] - vjp[1]) * (vip[1] - vjp[1]) \  
215 - + (vip[2] - vjp[2]) * (vip[2] - vjp[2]))  
216 - if distance <= dmax:  
217 - near_vertices.push_back(vj)  
218 - to_visit.push_back(vj)  
219 -  
220 - return near_vertices  
221 -  
222 -  
223 -cdef vector[weight_t]* calc_artifacts_weight(Mesh mesh, vector[vertex_id_t]& vertices_staircase, float tmax, float bmin) nogil:  
224 - """  
225 - Calculate the artifact weight based on distance of each vertex to its  
226 - nearest staircase artifact vertex.  
227 -  
228 - Params:  
229 - mesh: Mesh  
230 - vertices_staircase: the identified staircase artifact vertices  
231 - tmax: max distance the vertex must be to its nearest artifact vertex  
232 - to considered to calculate the weight  
233 - bmin: The minimum weight.  
234 - """  
235 - cdef int vi_id, vj_id, nnv, n_ids, i, j  
236 - cdef vector[vertex_id_t]* near_vertices  
237 - cdef weight_t value  
238 - cdef float d  
239 - n_ids = vertices_staircase.size()  
240 -  
241 - cdef vertex_t* vi  
242 - cdef vertex_t* vj  
243 - cdef size_t msize  
244 -  
245 - msize = mesh.vertices.shape[0]  
246 - cdef vector[weight_t]* weights = new vector[weight_t](msize)  
247 - weights.assign(msize, bmin)  
248 -  
249 - for i in prange(n_ids, nogil=True):  
250 - vi_id = vertices_staircase[i]  
251 - deref(weights)[vi_id] = 1.0  
252 -  
253 - vi = &mesh.vertices[vi_id, 0]  
254 - near_vertices = mesh.get_near_vertices_to_v(vi_id, tmax)  
255 - nnv = near_vertices.size()  
256 -  
257 - for j in xrange(nnv):  
258 - vj_id = deref(near_vertices)[j]  
259 - vj = &mesh.vertices[vj_id, 0]  
260 -  
261 - d = sqrt((vi[0] - vj[0]) * (vi[0] - vj[0])\  
262 - + (vi[1] - vj[1]) * (vi[1] - vj[1])\  
263 - + (vi[2] - vj[2]) * (vi[2] - vj[2]))  
264 - value = (1.0 - d/tmax) * (1.0 - bmin) + bmin  
265 -  
266 - if value > deref(weights)[vj_id]:  
267 - deref(weights)[vj_id] = value  
268 -  
269 - del near_vertices  
270 -  
271 - # for i in xrange(msize):  
272 - # if mesh.is_border(i):  
273 - # deref(weights)[i] = 0.0  
274 -  
275 - # cdef vertex_id_t v0, v1, v2  
276 - # for i in xrange(mesh.faces.shape[0]):  
277 - # for j in xrange(1, 4):  
278 - # v0 = mesh.faces[i, j]  
279 - # vi = &mesh.vertices[v0, 0]  
280 - # if mesh.is_border(v0):  
281 - # deref(weights)[v0] = 0.0  
282 - # v1 = mesh.faces[i, (j + 1) % 3 + 1]  
283 - # if mesh.is_border(v1):  
284 - # vi = &mesh.vertices[v1, 0]  
285 - # deref(weights)[v0] = 0.0  
286 -  
287 - return weights  
288 -  
289 -  
290 -cdef inline Point calc_d(Mesh mesh, vertex_id_t v_id) nogil:  
291 - cdef Point D  
292 - cdef int nf, f_id, nid  
293 - cdef float n=0  
294 - cdef int i  
295 - cdef vertex_t* vi  
296 - cdef vertex_t* vj  
297 - cdef set[vertex_id_t]* vertices  
298 - cdef set[vertex_id_t].iterator it  
299 - cdef vertex_id_t vj_id  
300 -  
301 - D.x = 0.0  
302 - D.y = 0.0  
303 - D.z = 0.0  
304 -  
305 - vertices = mesh.get_ring1(v_id)  
306 - vi = &mesh.vertices[v_id, 0]  
307 -  
308 - if mesh.is_border(v_id):  
309 - it = vertices.begin()  
310 - while it != vertices.end():  
311 - vj_id = deref(it)  
312 - if mesh.is_border(vj_id):  
313 - vj = &mesh.vertices[vj_id, 0]  
314 -  
315 - D.x = D.x + (vi[0] - vj[0])  
316 - D.y = D.y + (vi[1] - vj[1])  
317 - D.z = D.z + (vi[2] - vj[2])  
318 - n += 1.0  
319 -  
320 - inc(it)  
321 - else:  
322 - it = vertices.begin()  
323 - while it != vertices.end():  
324 - vj_id = deref(it)  
325 - vj = &mesh.vertices[vj_id, 0]  
326 -  
327 - D.x = D.x + (vi[0] - vj[0])  
328 - D.y = D.y + (vi[1] - vj[1])  
329 - D.z = D.z + (vi[2] - vj[2])  
330 - n += 1.0  
331 -  
332 - inc(it)  
333 -  
334 - del vertices  
335 -  
336 - D.x = D.x / n  
337 - D.y = D.y / n  
338 - D.z = D.z / n  
339 - return D  
340 -  
341 -cdef vector[vertex_id_t]* find_staircase_artifacts(Mesh mesh, double[3] stack_orientation, double T) nogil:  
342 - """  
343 - This function is used to find vertices at staircase artifacts, which are  
344 - those vertices whose incident faces' orientation differences are  
345 - greater than T.  
346 -  
347 - Params:  
348 - mesh: Mesh  
349 - stack_orientation: orientation of slice stacking  
350 - T: Min angle (between vertex faces and stack_orientation) to consider a  
351 - vertex a staircase artifact.  
352 - """  
353 - cdef int nv, nf, f_id, v_id  
354 - cdef double of_z, of_y, of_x, min_z, max_z, min_y, max_y, min_x, max_x;  
355 - cdef vector[vertex_id_t]* f_ids  
356 - cdef normal_t* normal  
357 -  
358 - cdef vector[vertex_id_t]* output = new vector[vertex_id_t]()  
359 - cdef int i  
360 -  
361 - nv = mesh.vertices.shape[0]  
362 -  
363 - for v_id in xrange(nv):  
364 - max_z = -10000  
365 - min_z = 10000  
366 - max_y = -10000  
367 - min_y = 10000  
368 - max_x = -10000  
369 - min_x = 10000  
370 -  
371 - f_ids = mesh.get_faces_by_vertex(v_id)  
372 - nf = deref(f_ids).size()  
373 -  
374 - for i in xrange(nf):  
375 - f_id = deref(f_ids)[i]  
376 - normal = &mesh.normals[f_id, 0]  
377 -  
378 - of_z = 1 - fabs(normal[0]*stack_orientation[0] + normal[1]*stack_orientation[1] + normal[2]*stack_orientation[2]);  
379 - of_y = 1 - fabs(normal[0]*0 + normal[1]*1 + normal[2]*0);  
380 - of_x = 1 - fabs(normal[0]*1 + normal[1]*0 + normal[2]*0);  
381 -  
382 - if (of_z > max_z):  
383 - max_z = of_z  
384 -  
385 - if (of_z < min_z):  
386 - min_z = of_z  
387 -  
388 - if (of_y > max_y):  
389 - max_y = of_y  
390 -  
391 - if (of_y < min_y):  
392 - min_y = of_y  
393 -  
394 - if (of_x > max_x):  
395 - max_x = of_x  
396 -  
397 - if (of_x < min_x):  
398 - min_x = of_x  
399 -  
400 -  
401 - if ((fabs(max_z - min_z) >= T) or (fabs(max_y - min_y) >= T) or (fabs(max_x - min_x) >= T)):  
402 - output.push_back(v_id)  
403 - break  
404 - return output  
405 -  
406 -  
407 -cdef void taubin_smooth(Mesh mesh, vector[weight_t]& weights, float l, float m, int steps):  
408 - """  
409 - Implementation of Taubin's smooth algorithm described in the paper "A  
410 - Signal Processing Approach To Fair Surface Design". His benefeat is it  
411 - avoids surface shrinking.  
412 - """  
413 - cdef int s, i, nvertices  
414 - nvertices = mesh.vertices.shape[0]  
415 - cdef vector[Point] D = vector[Point](nvertices)  
416 - cdef vertex_t* vi  
417 - for s in xrange(steps):  
418 - for i in prange(nvertices, nogil=True):  
419 - D[i] = calc_d(mesh, i)  
420 -  
421 - for i in prange(nvertices, nogil=True):  
422 - mesh.vertices[i, 0] += weights[i]*l*D[i].x;  
423 - mesh.vertices[i, 1] += weights[i]*l*D[i].y;  
424 - mesh.vertices[i, 2] += weights[i]*l*D[i].z;  
425 -  
426 - for i in prange(nvertices, nogil=True):  
427 - D[i] = calc_d(mesh, i)  
428 -  
429 - for i in prange(nvertices, nogil=True):  
430 - mesh.vertices[i, 0] += weights[i]*m*D[i].x;  
431 - mesh.vertices[i, 1] += weights[i]*m*D[i].y;  
432 - mesh.vertices[i, 2] += weights[i]*m*D[i].z;  
433 -  
434 -  
435 -def ca_smoothing(Mesh mesh, double T, double tmax, double bmin, int n_iters):  
436 - """  
437 - This is a implementation of the paper "Context-aware mesh smoothing for  
438 - biomedical applications". It can be used to smooth meshes generated by  
439 - binary images to remove its staircase artifacts and keep the fine features.  
440 -  
441 - Params:  
442 - mesh: Mesh  
443 - T: Min angle (between vertex faces and stack_orientation) to consider a  
444 - vertex a staircase artifact  
445 - tmax: max distance the vertex must be to its nearest artifact vertex  
446 - to considered to calculate the weight  
447 - bmin: The minimum weight  
448 - n_iters: Number of iterations.  
449 - """  
450 - cdef double[3] stack_orientation = [0.0, 0.0, 1.0]  
451 -  
452 - t0 = time.time()  
453 - cdef vector[vertex_id_t]* vertices_staircase = find_staircase_artifacts(mesh, stack_orientation, T)  
454 - print "vertices staircase", time.time() - t0  
455 -  
456 - t0 = time.time()  
457 - cdef vector[weight_t]* weights = calc_artifacts_weight(mesh, deref(vertices_staircase), tmax, bmin)  
458 - print "Weights", time.time() - t0  
459 -  
460 - del vertices_staircase  
461 -  
462 - t0 = time.time()  
463 - taubin_smooth(mesh, deref(weights), 0.5, -0.53, n_iters)  
464 - print "taubin", time.time() - t0  
465 -  
466 - del weights  
invesalius/data/cy_my_types.pxd
@@ -1,21 +0,0 @@ @@ -1,21 +0,0 @@
1 -import numpy as np  
2 -cimport numpy as np  
3 -cimport cython  
4 -  
5 -# ctypedef np.uint16_t image_t  
6 -  
7 -ctypedef fused image_t:  
8 - np.float64_t  
9 - np.int16_t  
10 - np.uint8_t  
11 -  
12 -ctypedef np.uint8_t mask_t  
13 -  
14 -ctypedef np.float32_t vertex_t  
15 -ctypedef np.float32_t normal_t  
16 -  
17 -# To compile in windows 64  
18 -IF UNAME_MACHINE == 'AMD64':  
19 - ctypedef np.int64_t vertex_id_t  
20 -ELSE:  
21 - ctypedef np.int_t vertex_id_t  
invesalius/data/floodfill.pyx
@@ -1,274 +0,0 @@ @@ -1,274 +0,0 @@
1 -import numpy as np  
2 -cimport numpy as np  
3 -cimport cython  
4 -  
5 -from collections import deque  
6 -  
7 -from cython.parallel import prange  
8 -from libc.math cimport floor, ceil  
9 -from libcpp cimport bool  
10 -from libcpp.deque cimport deque as cdeque  
11 -from libcpp.vector cimport vector  
12 -  
13 -from cy_my_types cimport image_t, mask_t  
14 -  
15 -cdef struct s_coord:  
16 - int x  
17 - int y  
18 - int z  
19 -  
20 -ctypedef s_coord coord  
21 -  
22 -  
23 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
24 -@cython.wraparound(False)  
25 -@cython.nonecheck(False)  
26 -@cython.cdivision(True)  
27 -cdef inline void append_queue(cdeque[int]& stack, int x, int y, int z, int d, int h, int w) nogil:  
28 - stack.push_back(z*h*w + y*w + x)  
29 -  
30 -  
31 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
32 -@cython.wraparound(False)  
33 -@cython.nonecheck(False)  
34 -@cython.cdivision(True)  
35 -cdef inline void pop_queue(cdeque[int]& stack, int* x, int* y, int* z, int d, int h, int w) nogil:  
36 - cdef int i = stack.front()  
37 - stack.pop_front()  
38 - x[0] = i % w  
39 - y[0] = (i / w) % h  
40 - z[0] = i / (h * w)  
41 -  
42 -  
43 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
44 -def floodfill(np.ndarray[image_t, ndim=3] data, int i, int j, int k, int v, int fill, np.ndarray[mask_t, ndim=3] out):  
45 -  
46 - cdef int to_return = 0  
47 - if out is None:  
48 - out = np.zeros_like(data)  
49 - to_return = 1  
50 -  
51 - cdef int x, y, z  
52 - cdef int w, h, d  
53 -  
54 - d = data.shape[0]  
55 - h = data.shape[1]  
56 - w = data.shape[2]  
57 -  
58 - stack = [(i, j, k), ]  
59 - out[k, j, i] = fill  
60 -  
61 - while stack:  
62 - x, y, z = stack.pop()  
63 -  
64 - if z + 1 < d and data[z + 1, y, x] == v and out[z + 1, y, x] != fill:  
65 - out[z + 1, y, x] = fill  
66 - stack.append((x, y, z + 1))  
67 -  
68 - if z - 1 >= 0 and data[z - 1, y, x] == v and out[z - 1, y, x] != fill:  
69 - out[z - 1, y, x] = fill  
70 - stack.append((x, y, z - 1))  
71 -  
72 - if y + 1 < h and data[z, y + 1, x] == v and out[z, y + 1, x] != fill:  
73 - out[z, y + 1, x] = fill  
74 - stack.append((x, y + 1, z))  
75 -  
76 - if y - 1 >= 0 and data[z, y - 1, x] == v and out[z, y - 1, x] != fill:  
77 - out[z, y - 1, x] = fill  
78 - stack.append((x, y - 1, z))  
79 -  
80 - if x + 1 < w and data[z, y, x + 1] == v and out[z, y, x + 1] != fill:  
81 - out[z, y, x + 1] = fill  
82 - stack.append((x + 1, y, z))  
83 -  
84 - if x - 1 >= 0 and data[z, y, x - 1] == v and out[z, y, x - 1] != fill:  
85 - out[z, y, x - 1] = fill  
86 - stack.append((x - 1, y, z))  
87 -  
88 - if to_return:  
89 - return out  
90 -  
91 -  
92 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
93 -@cython.wraparound(False)  
94 -@cython.nonecheck(False)  
95 -def floodfill_threshold(np.ndarray[image_t, ndim=3] data, list seeds, int t0, int t1, int fill, np.ndarray[mask_t, ndim=3] strct, np.ndarray[mask_t, ndim=3] out):  
96 -  
97 - cdef int to_return = 0  
98 - if out is None:  
99 - out = np.zeros_like(data)  
100 - to_return = 1  
101 -  
102 - cdef int x, y, z  
103 - cdef int dx, dy, dz  
104 - cdef int odx, ody, odz  
105 - cdef int xo, yo, zo  
106 - cdef int i, j, k  
107 - cdef int offset_x, offset_y, offset_z  
108 -  
109 - dz = data.shape[0]  
110 - dy = data.shape[1]  
111 - dx = data.shape[2]  
112 -  
113 - odz = strct.shape[0]  
114 - ody = strct.shape[1]  
115 - odx = strct.shape[2]  
116 -  
117 - cdef cdeque[coord] stack  
118 - cdef coord c  
119 -  
120 - offset_z = odz / 2  
121 - offset_y = ody / 2  
122 - offset_x = odx / 2  
123 -  
124 - for i, j, k in seeds:  
125 - if data[k, j, i] >= t0 and data[k, j, i] <= t1:  
126 - c.x = i  
127 - c.y = j  
128 - c.z = k  
129 - stack.push_back(c)  
130 - out[k, j, i] = fill  
131 -  
132 - with nogil:  
133 - while stack.size():  
134 - c = stack.back()  
135 - stack.pop_back()  
136 -  
137 - x = c.x  
138 - y = c.y  
139 - z = c.z  
140 -  
141 - out[z, y, x] = fill  
142 -  
143 - for k in xrange(odz):  
144 - zo = z + k - offset_z  
145 - for j in xrange(ody):  
146 - yo = y + j - offset_y  
147 - for i in xrange(odx):  
148 - if strct[k, j, i]:  
149 - xo = x + i - offset_x  
150 - if 0 <= xo < dx and 0 <= yo < dy and 0 <= zo < dz and out[zo, yo, xo] != fill and t0 <= data[zo, yo, xo] <= t1:  
151 - out[zo, yo, xo] = fill  
152 - c.x = xo  
153 - c.y = yo  
154 - c.z = zo  
155 - stack.push_back(c)  
156 -  
157 - if to_return:  
158 - return out  
159 -  
160 -  
161 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
162 -@cython.wraparound(False)  
163 -@cython.nonecheck(False)  
164 -def floodfill_auto_threshold(np.ndarray[image_t, ndim=3] data, list seeds, float p, int fill, np.ndarray[mask_t, ndim=3] out):  
165 -  
166 - cdef int to_return = 0  
167 - if out is None:  
168 - out = np.zeros_like(data)  
169 - to_return = 1  
170 -  
171 - cdef cdeque[int] stack  
172 - cdef int x, y, z  
173 - cdef int w, h, d  
174 - cdef int xo, yo, zo  
175 - cdef int t0, t1  
176 -  
177 - cdef int i, j, k  
178 -  
179 - d = data.shape[0]  
180 - h = data.shape[1]  
181 - w = data.shape[2]  
182 -  
183 -  
184 - # stack = deque()  
185 -  
186 - x = 0  
187 - y = 0  
188 - z = 0  
189 -  
190 -  
191 - for i, j, k in seeds:  
192 - append_queue(stack, i, j, k, d, h, w)  
193 - out[k, j, i] = fill  
194 - print i, j, k, d, h, w  
195 -  
196 - with nogil:  
197 - while stack.size():  
198 - pop_queue(stack, &x, &y, &z, d, h, w)  
199 -  
200 - # print x, y, z, d, h, w  
201 -  
202 - xo = x  
203 - yo = y  
204 - zo = z  
205 -  
206 - t0 = <int>ceil(data[z, y, x] * (1 - p))  
207 - t1 = <int>floor(data[z, y, x] * (1 + p))  
208 -  
209 - if z + 1 < d and data[z + 1, y, x] >= t0 and data[z + 1, y, x] <= t1 and out[zo + 1, yo, xo] != fill:  
210 - out[zo + 1, yo, xo] = fill  
211 - append_queue(stack, x, y, z+1, d, h, w)  
212 -  
213 - if z - 1 >= 0 and data[z - 1, y, x] >= t0 and data[z - 1, y, x] <= t1 and out[zo - 1, yo, xo] != fill:  
214 - out[zo - 1, yo, xo] = fill  
215 - append_queue(stack, x, y, z-1, d, h, w)  
216 -  
217 - if y + 1 < h and data[z, y + 1, x] >= t0 and data[z, y + 1, x] <= t1 and out[zo, yo + 1, xo] != fill:  
218 - out[zo, yo + 1, xo] = fill  
219 - append_queue(stack, x, y+1, z, d, h, w)  
220 -  
221 - if y - 1 >= 0 and data[z, y - 1, x] >= t0 and data[z, y - 1, x] <= t1 and out[zo, yo - 1, xo] != fill:  
222 - out[zo, yo - 1, xo] = fill  
223 - append_queue(stack, x, y-1, z, d, h, w)  
224 -  
225 - if x + 1 < w and data[z, y, x + 1] >= t0 and data[z, y, x + 1] <= t1 and out[zo, yo, xo + 1] != fill:  
226 - out[zo, yo, xo + 1] = fill  
227 - append_queue(stack, x+1, y, z, d, h, w)  
228 -  
229 - if x - 1 >= 0 and data[z, y, x - 1] >= t0 and data[z, y, x - 1] <= t1 and out[zo, yo, xo - 1] != fill:  
230 - out[zo, yo, xo - 1] = fill  
231 - append_queue(stack, x-1, y, z, d, h, w)  
232 -  
233 - if to_return:  
234 - return out  
235 -  
236 -  
237 -@cython.boundscheck(False)  
238 -@cython.wraparound(False)  
239 -@cython.nonecheck(False)  
240 -def fill_holes_automatically(np.ndarray[mask_t, ndim=3] mask, np.ndarray[np.uint16_t, ndim=3] labels, unsigned int nlabels, unsigned int max_size):  
241 - """  
242 - Fill mask holes automatically. The hole must <= max_size. Return True if any hole were filled.  
243 - """  
244 - cdef np.ndarray[np.uint32_t, ndim=1] sizes = np.zeros(shape=(nlabels + 1), dtype=np.uint32)  
245 - cdef int x, y, z  
246 - cdef int dx, dy, dz  
247 - cdef int i  
248 -  
249 - cdef bool modified = False  
250 -  
251 - dz = mask.shape[0]  
252 - dy = mask.shape[1]  
253 - dx = mask.shape[2]  
254 -  
255 - for z in xrange(dz):  
256 - for y in xrange(dy):  
257 - for x in xrange(dx):  
258 - sizes[labels[z, y, x]] += 1  
259 -  
260 - #Checking if any hole will be filled  
261 - for i in xrange(nlabels + 1):  
262 - if sizes[i] <= max_size:  
263 - modified = True  
264 -  
265 - if not modified:  
266 - return 0  
267 -  
268 - for z in prange(dz, nogil=True):  
269 - for y in xrange(dy):  
270 - for x in xrange(dx):  
271 - if sizes[labels[z, y, x]] <= max_size:  
272 - mask[z, y, x] = 254  
273 -  
274 - return modified  
invesalius/data/interpolation.pxd
@@ -1,8 +0,0 @@ @@ -1,8 +0,0 @@
1 -from .cy_my_types cimport image_t  
2 -  
3 -cdef double interpolate(image_t[:, :, :], double, double, double) nogil  
4 -cdef double tricub_interpolate(image_t[:, :, :], double, double, double) nogil  
5 -cdef double tricubicInterpolate (image_t[:, :, :], double, double, double) nogil  
6 -cdef double lanczos3 (image_t[:, :, :], double, double, double) nogil  
7 -  
8 -cdef double nearest_neighbour_interp(image_t[:, :, :], double, double, double) nogil  
invesalius/data/interpolation.pyx
@@ -1,392 +0,0 @@ @@ -1,392 +0,0 @@
1 -# from interpolation cimport interpolate  
2 -  
3 -import numpy as np  
4 -cimport numpy as np  
5 -cimport cython  
6 -  
7 -from libc.math cimport floor, ceil, sqrt, fabs, sin, M_PI  
8 -from cython.parallel import prange  
9 -  
10 -DEF LANCZOS_A = 4  
11 -DEF SIZE_LANCZOS_TMP = LANCZOS_A * 2 - 1  
12 -  
13 -cdef double[64][64] temp = [  
14 - [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
15 - [ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
16 - [-3, 3, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
17 - [ 2, -2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
18 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
19 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
20 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
21 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
22 - [-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
23 - [ 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
24 - [ 9, -9,-9, 9, 0, 0, 0, 0, 6, 3,-6,-3, 0, 0, 0, 0, 6,-6, 3,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
25 - [-6, 6, 6,-6, 0, 0, 0, 0,-3,-3, 3, 3, 0, 0, 0, 0,-4, 4,-2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-2,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
26 - [ 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
27 - [ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
28 - [-6, 6, 6,-6, 0, 0, 0, 0,-4,-2, 4, 2, 0, 0, 0, 0,-3, 3,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
29 - [ 4, -4,-4, 4, 0, 0, 0, 0, 2, 2,-2,-2, 0, 0, 0, 0, 2,-2, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
30 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
31 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
32 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
33 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
34 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
35 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],  
36 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0],  
37 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0],  
38 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
39 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0],  
40 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,-9,-9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3,-6,-3, 0, 0, 0, 0, 6,-6, 3,-3, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0],  
41 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3,-3, 3, 3, 0, 0, 0, 0,-4, 4,-2, 2, 0, 0, 0, 0,-2,-2,-1,-1, 0, 0, 0, 0],  
42 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
43 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0],  
44 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4,-2, 4, 2, 0, 0, 0, 0,-3, 3,-3, 3, 0, 0, 0, 0,-2,-1,-2,-1, 0, 0, 0, 0],  
45 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,-4,-4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,-2,-2, 0, 0, 0, 0, 2,-2, 2,-2, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],  
46 - [-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
47 - [ 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
48 - [ 9, -9, 0, 0,-9, 9, 0, 0, 6, 3, 0, 0,-6,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,-6, 0, 0, 3,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
49 - [-6, 6, 0, 0, 6,-6, 0, 0,-3,-3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 4, 0, 0,-2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-2, 0, 0,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
50 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
51 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0],  
52 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,-9, 0, 0,-9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, 0, 0,-6,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,-6, 0, 0, 3,-3, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0],  
53 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 0, 0, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3,-3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 4, 0, 0,-2, 2, 0, 0,-2,-2, 0, 0,-1,-1, 0, 0],  
54 - [ 9, 0,-9, 0,-9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0,-6, 0,-3, 0, 6, 0,-6, 0, 3, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
55 - [ 0, 0, 0, 0, 0, 0, 0, 0, 9, 0,-9, 0,-9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0,-6, 0,-3, 0, 6, 0,-6, 0, 3, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0],  
56 - [-27, 27,27,-27,27,-27,-27,27,-18,-9,18, 9,18, 9,-18,-9,-18,18,-9, 9,18,-18, 9,-9,-18,18,18,-18,-9, 9, 9,-9,-12,-6,-6,-3,12, 6, 6, 3,-12,-6,12, 6,-6,-3, 6, 3,-12,12,-6, 6,-6, 6,-3, 3,-8,-4,-4,-2,-4,-2,-2,-1],  
57 - [18, -18,-18,18,-18,18,18,-18, 9, 9,-9,-9,-9,-9, 9, 9,12,-12, 6,-6,-12,12,-6, 6,12,-12,-12,12, 6,-6,-6, 6, 6, 6, 3, 3,-6,-6,-3,-3, 6, 6,-6,-6, 3, 3,-3,-3, 8,-8, 4,-4, 4,-4, 2,-2, 4, 4, 2, 2, 2, 2, 1, 1],  
58 - [-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0,-3, 0, 3, 0, 3, 0,-4, 0, 4, 0,-2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-2, 0,-1, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
59 - [ 0, 0, 0, 0, 0, 0, 0, 0,-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0,-3, 0, 3, 0, 3, 0,-4, 0, 4, 0,-2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-2, 0,-1, 0,-1, 0],  
60 - [18, -18,-18,18,-18,18,18,-18,12, 6,-12,-6,-12,-6,12, 6, 9,-9, 9,-9,-9, 9,-9, 9,12,-12,-12,12, 6,-6,-6, 6, 6, 3, 6, 3,-6,-3,-6,-3, 8, 4,-8,-4, 4, 2,-4,-2, 6,-6, 6,-6, 3,-3, 3,-3, 4, 2, 4, 2, 2, 1, 2, 1],  
61 - [-12, 12,12,-12,12,-12,-12,12,-6,-6, 6, 6, 6, 6,-6,-6,-6, 6,-6, 6, 6,-6, 6,-6,-8, 8, 8,-8,-4, 4, 4,-4,-3,-3,-3,-3, 3, 3, 3, 3,-4,-4, 4, 4,-2,-2, 2, 2,-4, 4,-4, 4,-2, 2,-2, 2,-2,-2,-2,-2,-1,-1,-1,-1],  
62 - [ 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
63 - [ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
64 - [-6, 6, 0, 0, 6,-6, 0, 0,-4,-2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
65 - [ 4, -4, 0, 0,-4, 4, 0, 0, 2, 2, 0, 0,-2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
66 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
67 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],  
68 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 0, 0, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4,-2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0,-3, 3, 0, 0,-2,-1, 0, 0,-2,-1, 0, 0],  
69 - [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,-4, 0, 0,-4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0,-2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 2,-2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0],  
70 - [-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0,-2, 0, 4, 0, 2, 0,-3, 0, 3, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
71 - [ 0, 0, 0, 0, 0, 0, 0, 0,-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0,-2, 0, 4, 0, 2, 0,-3, 0, 3, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0,-2, 0,-1, 0],  
72 - [18, -18,-18,18,-18,18,18,-18,12, 6,-12,-6,-12,-6,12, 6,12,-12, 6,-6,-12,12,-6, 6, 9,-9,-9, 9, 9,-9,-9, 9, 8, 4, 4, 2,-8,-4,-4,-2, 6, 3,-6,-3, 6, 3,-6,-3, 6,-6, 3,-3, 6,-6, 3,-3, 4, 2, 2, 1, 4, 2, 2, 1],  
73 - [-12, 12,12,-12,12,-12,-12,12,-6,-6, 6, 6, 6, 6,-6,-6,-8, 8,-4, 4, 8,-8, 4,-4,-6, 6, 6,-6,-6, 6, 6,-6,-4,-4,-2,-2, 4, 4, 2, 2,-3,-3, 3, 3,-3,-3, 3, 3,-4, 4,-2, 2,-4, 4,-2, 2,-2,-2,-1,-1,-2,-2,-1,-1],  
74 - [ 4, 0,-4, 0,-4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0,-2, 0,-2, 0, 2, 0,-2, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],  
75 - [ 0, 0, 0, 0, 0, 0, 0, 0, 4, 0,-4, 0,-4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0,-2, 0,-2, 0, 2, 0,-2, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0],  
76 - [-12, 12,12,-12,12,-12,-12,12,-8,-4, 8, 4, 8, 4,-8,-4,-6, 6,-6, 6, 6,-6, 6,-6,-6, 6, 6,-6,-6, 6, 6,-6,-4,-2,-4,-2, 4, 2, 4, 2,-4,-2, 4, 2,-4,-2, 4, 2,-3, 3,-3, 3,-3, 3,-3, 3,-2,-1,-2,-1,-2,-1,-2,-1],  
77 - [ 8, -8,-8, 8,-8, 8, 8,-8, 4, 4,-4,-4,-4,-4, 4, 4, 4,-4, 4,-4,-4, 4,-4, 4, 4,-4,-4, 4, 4,-4,-4, 4, 2, 2, 2, 2,-2,-2,-2,-2, 2, 2,-2,-2, 2, 2,-2,-2, 2,-2, 2,-2, 2,-2, 2,-2, 1, 1, 1, 1, 1, 1, 1, 1]  
78 -]  
79 -  
80 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
81 -@cython.cdivision(True)  
82 -@cython.wraparound(False)  
83 -cdef double nearest_neighbour_interp(image_t[:, :, :] V, double x, double y, double z) nogil:  
84 - return V[<int>(z), <int>(y), <int>(x)]  
85 -  
86 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
87 -@cython.cdivision(True)  
88 -@cython.wraparound(False)  
89 -cdef double interpolate(image_t[:, :, :] V, double x, double y, double z) nogil:  
90 - cdef double xd, yd, zd  
91 - cdef double c00, c10, c01, c11  
92 - cdef double c0, c1  
93 - cdef double c  
94 -  
95 - cdef int x0 = <int>floor(x)  
96 - cdef int x1 = x0 + 1  
97 -  
98 - cdef int y0 = <int>floor(y)  
99 - cdef int y1 = y0 + 1  
100 -  
101 - cdef int z0 = <int>floor(z)  
102 - cdef int z1 = z0 + 1  
103 -  
104 - if x0 == x1:  
105 - xd = 1.0  
106 - else:  
107 - xd = (x - x0) / (x1 - x0)  
108 -  
109 - if y0 == y1:  
110 - yd = 1.0  
111 - else:  
112 - yd = (y - y0) / (y1 - y0)  
113 -  
114 - if z0 == z1:  
115 - zd = 1.0  
116 - else:  
117 - zd = (z - z0) / (z1 - z0)  
118 -  
119 - c00 = _G(V, x0, y0, z0)*(1 - xd) + _G(V, x1, y0, z0)*xd  
120 - c10 = _G(V, x0, y1, z0)*(1 - xd) + _G(V, x1, y1, z0)*xd  
121 - c01 = _G(V, x0, y0, z1)*(1 - xd) + _G(V, x1, y0, z1)*xd  
122 - c11 = _G(V, x0, y1, z1)*(1 - xd) + _G(V, x1, y1, z1)*xd  
123 -  
124 - c0 = c00*(1 - yd) + c10*yd  
125 - c1 = c01*(1 - yd) + c11*yd  
126 -  
127 - c = c0*(1 - zd) + c1*zd  
128 -  
129 - return c  
130 -  
131 -  
132 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
133 -@cython.cdivision(True)  
134 -@cython.wraparound(False)  
135 -cdef inline double lanczos3_L(double x, int a) nogil:  
136 - if x == 0:  
137 - return 1.0  
138 - elif -a <= x < a:  
139 - return (a * sin(M_PI * x) * sin(M_PI * (x / a)))/(M_PI**2 * x**2)  
140 - else:  
141 - return 0.0  
142 -  
143 -  
144 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
145 -@cython.cdivision(True)  
146 -@cython.wraparound(False)  
147 -cdef double lanczos3(image_t[:, :, :] V, double x, double y, double z) nogil:  
148 - cdef int a = LANCZOS_A  
149 -  
150 - cdef int xd = <int>floor(x)  
151 - cdef int yd = <int>floor(y)  
152 - cdef int zd = <int>floor(z)  
153 -  
154 - cdef int xi = xd - a + 1  
155 - cdef int xf = xd + a  
156 -  
157 - cdef int yi = yd - a + 1  
158 - cdef int yf = yd + a  
159 -  
160 - cdef int zi = zd - a + 1  
161 - cdef int zf = zd + a  
162 -  
163 - cdef double lx = 0.0  
164 - cdef double ly = 0.0  
165 - cdef double lz = 0.0  
166 -  
167 - cdef double[SIZE_LANCZOS_TMP][SIZE_LANCZOS_TMP] temp_x  
168 - cdef double[SIZE_LANCZOS_TMP] temp_y  
169 -  
170 - cdef int i, j, k  
171 - cdef int m, n, o  
172 -  
173 - m = 0  
174 - for k in xrange(zi, zf):  
175 - n = 0  
176 - for j in xrange(yi, yf):  
177 - lx = 0  
178 - for i in xrange(xi, xf):  
179 - lx += _G(V, i, j, k) * lanczos3_L(x - i, a)  
180 - temp_x[m][n] = lx  
181 - n += 1  
182 - m += 1  
183 -  
184 - m = 0  
185 - for k in xrange(zi, zf):  
186 - n = 0  
187 - ly = 0  
188 - for j in xrange(yi, yf):  
189 - ly += temp_x[m][n] * lanczos3_L(y - j, a)  
190 - n += 1  
191 - temp_y[m] = ly  
192 - m += 1  
193 -  
194 - m = 0  
195 - for k in xrange(zi, zf):  
196 - lz += temp_y[m] * lanczos3_L(z - k, a)  
197 - m += 1  
198 -  
199 - return lz  
200 -  
201 -  
202 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
203 -@cython.cdivision(True)  
204 -@cython.wraparound(False)  
205 -cdef image_t _G(image_t[:, :, :] V, int x, int y, int z) nogil:  
206 - cdef int dz, dy, dx  
207 - dz = V.shape[0] - 1  
208 - dy = V.shape[1] - 1  
209 - dx = V.shape[2] - 1  
210 -  
211 - if x < 0:  
212 - x = dx + x + 1  
213 - elif x > dx:  
214 - x = x - dx - 1  
215 -  
216 - if y < 0:  
217 - y = dy + y + 1  
218 - elif y > dy:  
219 - y = y - dy - 1  
220 -  
221 - if z < 0:  
222 - z = dz + z + 1  
223 - elif z > dz:  
224 - z = z - dz - 1  
225 -  
226 - return V[z, y, x]  
227 -  
228 -  
229 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
230 -@cython.cdivision(True)  
231 -@cython.wraparound(False)  
232 -cdef void calc_coef_tricub(image_t[:, :, :] V, double x, double y, double z, double [64] coef) nogil:  
233 - cdef int xi = <int>floor(x)  
234 - cdef int yi = <int>floor(y)  
235 - cdef int zi = <int>floor(z)  
236 -  
237 - cdef double[64] _x  
238 -  
239 - cdef int i, j  
240 -  
241 - _x[0] = _G(V, xi, yi, zi)  
242 - _x[1] = _G(V, xi + 1, yi, zi)  
243 - _x[2] = _G(V, xi, yi + 1, zi)  
244 - _x[3] = _G(V, xi + 1, yi + 1, zi)  
245 - _x[4] = _G(V, xi, yi, zi + 1)  
246 - _x[5] = _G(V, xi + 1, yi, zi + 1)  
247 - _x[6] = _G(V, xi, yi + 1, zi + 1)  
248 - _x[7] = _G(V, xi + 1, yi + 1, zi + 1)  
249 -  
250 - _x[8] = 0.5*(_G(V, xi+1,yi,zi) - _G(V, xi-1, yi, zi))  
251 - _x[9] = 0.5*(_G(V, xi+2,yi,zi) - _G(V, xi, yi, zi))  
252 - _x[10] = 0.5*(_G(V, xi+1, yi+1,zi) - _G(V, xi-1, yi+1, zi))  
253 - _x[11] = 0.5*(_G(V, xi+2, yi+1,zi) - _G(V, xi, yi+1, zi))  
254 - _x[12] = 0.5*(_G(V, xi+1, yi,zi+1) - _G(V, xi-1, yi, zi+1))  
255 - _x[13] = 0.5*(_G(V, xi+2, yi,zi+1) - _G(V, xi, yi, zi+1))  
256 - _x[14] = 0.5*(_G(V, xi+1, yi+1,zi+1) - _G(V, xi-1, yi+1, zi+1))  
257 - _x[15] = 0.5*(_G(V, xi+2, yi+1,zi+1) - _G(V, xi, yi+1, zi+1))  
258 - _x[16] = 0.5*(_G(V, xi, yi+1,zi) - _G(V, xi, yi-1, zi))  
259 - _x[17] = 0.5*(_G(V, xi+1, yi+1,zi) - _G(V, xi+1, yi-1, zi))  
260 - _x[18] = 0.5*(_G(V, xi, yi+2,zi) - _G(V, xi, yi, zi))  
261 - _x[19] = 0.5*(_G(V, xi+1, yi+2,zi) - _G(V, xi+1, yi, zi))  
262 - _x[20] = 0.5*(_G(V, xi, yi+1,zi+1) - _G(V, xi, yi-1, zi+1))  
263 - _x[21] = 0.5*(_G(V, xi+1, yi+1,zi+1) - _G(V, xi+1, yi-1, zi+1))  
264 - _x[22] = 0.5*(_G(V, xi, yi+2,zi+1) - _G(V, xi, yi, zi+1))  
265 - _x[23] = 0.5*(_G(V, xi+1, yi+2,zi+1) - _G(V, xi+1, yi, zi+1))  
266 - _x[24] = 0.5*(_G(V, xi, yi,zi+1) - _G(V, xi, yi, zi-1))  
267 - _x[25] = 0.5*(_G(V, xi+1, yi,zi+1) - _G(V, xi+1, yi, zi-1))  
268 - _x[26] = 0.5*(_G(V, xi, yi+1,zi+1) - _G(V, xi, yi+1, zi-1))  
269 - _x[27] = 0.5*(_G(V, xi+1, yi+1,zi+1) - _G(V, xi+1, yi+1, zi-1))  
270 - _x[28] = 0.5*(_G(V, xi, yi,zi+2) - _G(V, xi, yi, zi))  
271 - _x[29] = 0.5*(_G(V, xi+1, yi,zi+2) - _G(V, xi+1, yi, zi))  
272 - _x[30] = 0.5*(_G(V, xi, yi+1,zi+2) - _G(V, xi, yi+1, zi))  
273 - _x[31] = 0.5*(_G(V, xi+1, yi+1,zi+2) - _G(V, xi+1, yi+1, zi))  
274 -  
275 - _x [32] = 0.25*(_G(V, xi+1, yi+1, zi) - _G(V, xi-1, yi+1, zi) - _G(V, xi+1, yi-1, zi) + _G(V, xi-1, yi-1, zi))  
276 - _x [33] = 0.25*(_G(V, xi+2, yi+1, zi) - _G(V, xi, yi+1, zi) - _G(V, xi+2, yi-1, zi) + _G(V, xi, yi-1, zi))  
277 - _x [34] = 0.25*(_G(V, xi+1, yi+2, zi) - _G(V, xi-1, yi+2, zi) - _G(V, xi+1, yi, zi) + _G(V, xi-1, yi, zi))  
278 - _x [35] = 0.25*(_G(V, xi+2, yi+2, zi) - _G(V, xi, yi+2, zi) - _G(V, xi+2, yi, zi) + _G(V, xi, yi, zi))  
279 - _x [36] = 0.25*(_G(V, xi+1, yi+1, zi+1) - _G(V, xi-1, yi+1, zi+1) - _G(V, xi+1, yi-1, zi+1) + _G(V, xi-1, yi-1, zi+1))  
280 - _x [37] = 0.25*(_G(V, xi+2, yi+1, zi+1) - _G(V, xi, yi+1, zi+1) - _G(V, xi+2, yi-1, zi+1) + _G(V, xi, yi-1, zi+1))  
281 - _x [38] = 0.25*(_G(V, xi+1, yi+2, zi+1) - _G(V, xi-1, yi+2, zi+1) - _G(V, xi+1, yi, zi+1) + _G(V, xi-1, yi, zi+1))  
282 - _x [39] = 0.25*(_G(V, xi+2, yi+2, zi+1) - _G(V, xi, yi+2, zi+1) - _G(V, xi+2, yi, zi+1) + _G(V, xi, yi, zi+1))  
283 - _x [40] = 0.25*(_G(V, xi+1, yi, zi+1) - _G(V, xi-1, yi, zi+1) - _G(V, xi+1, yi, zi-1) + _G(V, xi-1, yi, zi-1))  
284 - _x [41] = 0.25*(_G(V, xi+2, yi, zi+1) - _G(V, xi, yi, zi+1) - _G(V, xi+2, yi, zi-1) + _G(V, xi, yi, zi-1))  
285 - _x [42] = 0.25*(_G(V, xi+1, yi+1, zi+1) - _G(V, xi-1, yi+1, zi+1) - _G(V, xi+1, yi+1, zi-1) + _G(V, xi-1, yi+1, zi-1))  
286 - _x [43] = 0.25*(_G(V, xi+2, yi+1, zi+1) - _G(V, xi, yi+1, zi+1) - _G(V, xi+2, yi+1, zi-1) + _G(V, xi, yi+1, zi-1))  
287 - _x [44] = 0.25*(_G(V, xi+1, yi, zi+2) - _G(V, xi-1, yi, zi+2) - _G(V, xi+1, yi, zi) + _G(V, xi-1, yi, zi))  
288 - _x [45] = 0.25*(_G(V, xi+2, yi, zi+2) - _G(V, xi, yi, zi+2) - _G(V, xi+2, yi, zi) + _G(V, xi, yi, zi))  
289 - _x [46] = 0.25*(_G(V, xi+1, yi+1, zi+2) - _G(V, xi-1, yi+1, zi+2) - _G(V, xi+1, yi+1, zi) + _G(V, xi-1, yi+1, zi))  
290 - _x [47] = 0.25*(_G(V, xi+2, yi+1, zi+2) - _G(V, xi, yi+1, zi+2) - _G(V, xi+2, yi+1, zi) + _G(V, xi, yi+1, zi))  
291 - _x [48] = 0.25*(_G(V, xi, yi+1, zi+1) - _G(V, xi, yi-1, zi+1) - _G(V, xi, yi+1, zi-1) + _G(V, xi, yi-1, zi-1))  
292 - _x [49] = 0.25*(_G(V, xi+1, yi+1, zi+1) - _G(V, xi+1, yi-1, zi+1) - _G(V, xi+1, yi+1, zi-1) + _G(V, xi+1, yi-1, zi-1))  
293 - _x [50] = 0.25*(_G(V, xi, yi+2, zi+1) - _G(V, xi, yi, zi+1) - _G(V, xi, yi+2, zi-1) + _G(V, xi, yi, zi-1))  
294 - _x [51] = 0.25*(_G(V, xi+1, yi+2, zi+1) - _G(V, xi+1, yi, zi+1) - _G(V, xi+1, yi+2, zi-1) + _G(V, xi+1, yi, zi-1))  
295 - _x [52] = 0.25*(_G(V, xi, yi+1, zi+2) - _G(V, xi, yi-1, zi+2) - _G(V, xi, yi+1, zi) + _G(V, xi, yi-1, zi))  
296 - _x [53] = 0.25*(_G(V, xi+1, yi+1, zi+2) - _G(V, xi+1, yi-1, zi+2) - _G(V, xi+1, yi+1, zi) + _G(V, xi+1, yi-1, zi))  
297 - _x [54] = 0.25*(_G(V, xi, yi+2, zi+2) - _G(V, xi, yi, zi+2) - _G(V, xi, yi+2, zi) + _G(V, xi, yi, zi))  
298 - _x [55] = 0.25*(_G(V, xi+1, yi+2, zi+2) - _G(V, xi+1, yi, zi+2) - _G(V, xi+1, yi+2, zi) + _G(V, xi+1, yi, zi))  
299 -  
300 - _x[56] = 0.125*(_G(V, xi+1, yi+1, zi+1) - _G(V, xi-1, yi+1, zi+1) - _G(V, xi+1, yi-1, zi+1) + _G(V, xi-1, yi-1, zi+1) - _G(V, xi+1, yi+1, zi-1) + _G(V, xi-1,yi+1,zi-1)+_G(V, xi+1,yi-1,zi-1)-_G(V, xi-1,yi-1,zi-1))  
301 - _x[57] = 0.125*(_G(V, xi+2, yi+1, zi+1) - _G(V, xi, yi+1, zi+1) - _G(V, xi+2, yi-1, zi+1) + _G(V, xi, yi-1, zi+1) - _G(V, xi+2, yi+1, zi-1) + _G(V, xi,yi+1,zi-1)+_G(V, xi+2,yi-1,zi-1)-_G(V, xi,yi-1,zi-1))  
302 - _x[58] = 0.125*(_G(V, xi+1, yi+2, zi+1) - _G(V, xi-1, yi+2, zi+1) - _G(V, xi+1, yi, zi+1) + _G(V, xi-1, yi, zi+1) - _G(V, xi+1, yi+2, zi-1) + _G(V, xi-1,yi+2,zi-1)+_G(V, xi+1,yi,zi-1)-_G(V, xi-1,yi,zi-1))  
303 - _x[59] = 0.125*(_G(V, xi+2, yi+2, zi+1) - _G(V, xi, yi+2, zi+1) - _G(V, xi+2, yi, zi+1) + _G(V, xi, yi, zi+1) - _G(V, xi+2, yi+2, zi-1) + _G(V, xi,yi+2,zi-1)+_G(V, xi+2,yi,zi-1)-_G(V, xi,yi,zi-1))  
304 - _x[60] = 0.125*(_G(V, xi+1, yi+1, zi+2) - _G(V, xi-1, yi+1, zi+2) - _G(V, xi+1, yi-1, zi+2) + _G(V, xi-1, yi-1, zi+2) - _G(V, xi+1, yi+1, zi) + _G(V, xi-1,yi+1,zi)+_G(V, xi+1,yi-1,zi)-_G(V, xi-1,yi-1,zi))  
305 - _x[61] = 0.125*(_G(V, xi+2, yi+1, zi+2) - _G(V, xi, yi+1, zi+2) - _G(V, xi+2, yi-1, zi+2) + _G(V, xi, yi-1, zi+2) - _G(V, xi+2, yi+1, zi) + _G(V, xi,yi+1,zi)+_G(V, xi+2,yi-1,zi)-_G(V, xi,yi-1,zi))  
306 - _x[62] = 0.125*(_G(V, xi+1, yi+2, zi+2) - _G(V, xi-1, yi+2, zi+2) - _G(V, xi+1, yi, zi+2) + _G(V, xi-1, yi, zi+2) - _G(V, xi+1, yi+2, zi) + _G(V, xi-1,yi+2,zi)+_G(V, xi+1,yi,zi)-_G(V, xi-1,yi,zi))  
307 - _x[63] = 0.125*(_G(V, xi+2, yi+2, zi+2) - _G(V, xi, yi+2, zi+2) - _G(V, xi+2, yi, zi+2) + _G(V, xi, yi, zi+2) - _G(V, xi+2, yi+2, zi) + _G(V, xi,yi+2,zi)+_G(V, xi+2,yi,zi)-_G(V, xi,yi,zi))  
308 -  
309 - for j in prange(64):  
310 - coef[j] = 0.0  
311 - for i in xrange(64):  
312 - coef[j] += (temp[j][i] * _x[i])  
313 -  
314 -  
315 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
316 -@cython.cdivision(True)  
317 -@cython.wraparound(False)  
318 -cdef double tricub_interpolate(image_t[:, :, :] V, double x, double y, double z) nogil:  
319 - # From: Tricubic interpolation in three dimensions. Lekien and Marsden  
320 - cdef double[64] coef  
321 - cdef double result = 0.0  
322 - calc_coef_tricub(V, x, y, z, coef)  
323 -  
324 - cdef int i, j, k  
325 -  
326 - cdef int xi = <int>floor(x)  
327 - cdef int yi = <int>floor(y)  
328 - cdef int zi = <int>floor(z)  
329 -  
330 - for i in xrange(4):  
331 - for j in xrange(4):  
332 - for k in xrange(4):  
333 - result += (coef[i+4*j+16*k] * ((x-xi)**i) * ((y-yi)**j) * ((z-zi)**k))  
334 - # return V[<int>z, <int>y, <int>x]  
335 - # with gil:  
336 - # print result  
337 - return result  
338 -  
339 -  
340 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
341 -@cython.cdivision(True)  
342 -@cython.wraparound(False)  
343 -cdef double cubicInterpolate(double p[4], double x) nogil:  
344 - return p[1] + 0.5 * x*(p[2] - p[0] + x*(2.0*p[0] - 5.0*p[1] + 4.0*p[2] - p[3] + x*(3.0*(p[1] - p[2]) + p[3] - p[0])))  
345 -  
346 -  
347 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
348 -@cython.cdivision(True)  
349 -@cython.wraparound(False)  
350 -cdef double bicubicInterpolate (double p[4][4], double x, double y) nogil:  
351 - cdef double arr[4]  
352 - arr[0] = cubicInterpolate(p[0], y)  
353 - arr[1] = cubicInterpolate(p[1], y)  
354 - arr[2] = cubicInterpolate(p[2], y)  
355 - arr[3] = cubicInterpolate(p[3], y)  
356 - return cubicInterpolate(arr, x)  
357 -  
358 -  
359 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
360 -@cython.cdivision(True)  
361 -@cython.wraparound(False)  
362 -cdef double tricubicInterpolate(image_t[:, :, :] V, double x, double y, double z) nogil:  
363 - # From http://www.paulinternet.nl/?page=bicubic  
364 - cdef double p[4][4][4]  
365 -  
366 - cdef int xi = <int>floor(x)  
367 - cdef int yi = <int>floor(y)  
368 - cdef int zi = <int>floor(z)  
369 -  
370 - cdef int i, j, k  
371 -  
372 - for i in xrange(4):  
373 - for j in xrange(4):  
374 - for k in xrange(4):  
375 - p[i][j][k] = _G(V, xi + i -1, yi + j -1, zi + k - 1)  
376 -  
377 - cdef double arr[4]  
378 - arr[0] = bicubicInterpolate(p[0], y-yi, z-zi)  
379 - arr[1] = bicubicInterpolate(p[1], y-yi, z-zi)  
380 - arr[2] = bicubicInterpolate(p[2], y-yi, z-zi)  
381 - arr[3] = bicubicInterpolate(p[3], y-yi, z-zi)  
382 - return cubicInterpolate(arr, x-xi)  
383 -  
384 -  
385 -def tricub_interpolate_py(image_t[:, :, :] V, double x, double y, double z):  
386 - return tricub_interpolate(V, x, y, z)  
387 -  
388 -def tricub_interpolate2_py(image_t[:, :, :] V, double x, double y, double z):  
389 - return tricubicInterpolate(V, x, y, z)  
390 -  
391 -def trilin_interpolate_py(image_t[:, :, :] V, double x, double y, double z):  
392 - return interpolate(V, x, y, z)  
invesalius/data/mask.py
@@ -30,7 +30,7 @@ import invesalius.constants as const @@ -30,7 +30,7 @@ import invesalius.constants as const
30 import invesalius.data.imagedata_utils as iu 30 import invesalius.data.imagedata_utils as iu
31 import invesalius.session as ses 31 import invesalius.session as ses
32 32
33 -from . import floodfill 33 +from invesalius_cy import floodfill
34 34
35 from wx.lib.pubsub import pub as Publisher 35 from wx.lib.pubsub import pub as Publisher
36 from scipy import ndimage 36 from scipy import ndimage
invesalius/data/mips.pyx
@@ -1,379 +0,0 @@ @@ -1,379 +0,0 @@
1 -#http://en.wikipedia.org/wiki/Local_maximum_intensity_projection  
2 -import numpy as np  
3 -cimport numpy as np  
4 -cimport cython  
5 -  
6 -from libc.math cimport floor, ceil, sqrt, fabs  
7 -from cython.parallel import prange  
8 -  
9 -DTYPE = np.uint8  
10 -ctypedef np.uint8_t DTYPE_t  
11 -  
12 -DTYPE16 = np.int16  
13 -ctypedef np.int16_t DTYPE16_t  
14 -  
15 -DTYPEF32 = np.float32  
16 -ctypedef np.float32_t DTYPEF32_t  
17 -  
18 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
19 -def lmip(np.ndarray[DTYPE16_t, ndim=3] image, int axis, DTYPE16_t tmin,  
20 - DTYPE16_t tmax, np.ndarray[DTYPE16_t, ndim=2] out):  
21 - cdef DTYPE16_t max  
22 - cdef int start  
23 - cdef int sz = image.shape[0]  
24 - cdef int sy = image.shape[1]  
25 - cdef int sx = image.shape[2]  
26 -  
27 - # AXIAL  
28 - if axis == 0:  
29 - for x in xrange(sx):  
30 - for y in xrange(sy):  
31 - max = image[0, y, x]  
32 - if max >= tmin and max <= tmax:  
33 - start = 1  
34 - else:  
35 - start = 0  
36 - for z in xrange(sz):  
37 - if image[z, y, x] > max:  
38 - max = image[z, y, x]  
39 -  
40 - elif image[z, y, x] < max and start:  
41 - break  
42 -  
43 - if image[z, y, x] >= tmin and image[z, y, x] <= tmax:  
44 - start = 1  
45 -  
46 - out[y, x] = max  
47 -  
48 - #CORONAL  
49 - elif axis == 1:  
50 - for z in xrange(sz):  
51 - for x in xrange(sx):  
52 - max = image[z, 0, x]  
53 - if max >= tmin and max <= tmax:  
54 - start = 1  
55 - else:  
56 - start = 0  
57 - for y in xrange(sy):  
58 - if image[z, y, x] > max:  
59 - max = image[z, y, x]  
60 -  
61 - elif image[z, y, x] < max and start:  
62 - break  
63 -  
64 - if image[z, y, x] >= tmin and image[z, y, x] <= tmax:  
65 - start = 1  
66 -  
67 - out[z, x] = max  
68 -  
69 - #CORONAL  
70 - elif axis == 2:  
71 - for z in xrange(sz):  
72 - for y in xrange(sy):  
73 - max = image[z, y, 0]  
74 - if max >= tmin and max <= tmax:  
75 - start = 1  
76 - else:  
77 - start = 0  
78 - for x in xrange(sx):  
79 - if image[z, y, x] > max:  
80 - max = image[z, y, x]  
81 -  
82 - elif image[z, y, x] < max and start:  
83 - break  
84 -  
85 - if image[z, y, x] >= tmin and image[z, y, x] <= tmax:  
86 - start = 1  
87 -  
88 - out[z, y] = max  
89 -  
90 -  
91 -cdef DTYPE16_t get_colour(DTYPE16_t vl, DTYPE16_t wl, DTYPE16_t ww):  
92 - cdef DTYPE16_t out_colour  
93 - cdef DTYPE16_t min_value = wl - (ww / 2)  
94 - cdef DTYPE16_t max_value = wl + (ww / 2)  
95 - if vl < min_value:  
96 - out_colour = min_value  
97 - elif vl > max_value:  
98 - out_colour = max_value  
99 - else:  
100 - out_colour = vl  
101 -  
102 - return out_colour  
103 -  
104 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
105 -@cython.cdivision(True)  
106 -cdef float get_opacity(DTYPE16_t vl, DTYPE16_t wl, DTYPE16_t ww) nogil:  
107 - cdef float out_opacity  
108 - cdef DTYPE16_t min_value = wl - (ww / 2)  
109 - cdef DTYPE16_t max_value = wl + (ww / 2)  
110 - if vl < min_value:  
111 - out_opacity = 0.0  
112 - elif vl > max_value:  
113 - out_opacity = 1.0  
114 - else:  
115 - out_opacity = 1.0/(max_value - min_value) * (vl - min_value)  
116 -  
117 - return out_opacity  
118 -  
119 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
120 -@cython.cdivision(True)  
121 -cdef float get_opacity_f32(DTYPEF32_t vl, DTYPE16_t wl, DTYPE16_t ww) nogil:  
122 - cdef float out_opacity  
123 - cdef DTYPE16_t min_value = wl - (ww / 2)  
124 - cdef DTYPE16_t max_value = wl + (ww / 2)  
125 - if vl < min_value:  
126 - out_opacity = 0.0  
127 - elif vl > max_value:  
128 - out_opacity = 1.0  
129 - else:  
130 - out_opacity = 1.0/(max_value - min_value) * (vl - min_value)  
131 -  
132 - return out_opacity  
133 -  
134 -  
135 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
136 -@cython.cdivision(True)  
137 -def mida(np.ndarray[DTYPE16_t, ndim=3] image, int axis, DTYPE16_t wl,  
138 - DTYPE16_t ww, np.ndarray[DTYPE16_t, ndim=2] out):  
139 - cdef int sz = image.shape[0]  
140 - cdef int sy = image.shape[1]  
141 - cdef int sx = image.shape[2]  
142 -  
143 - cdef DTYPE16_t min = image.min()  
144 - cdef DTYPE16_t max = image.max()  
145 - cdef DTYPE16_t vl  
146 -  
147 - cdef DTYPE16_t min_value = wl - (ww / 2)  
148 - cdef DTYPE16_t max_value = wl + (ww / 2)  
149 -  
150 - cdef float fmax=0.0  
151 - cdef float fpi  
152 - cdef float dl  
153 - cdef float bt  
154 -  
155 - cdef float alpha  
156 - cdef float alpha_p = 0.0  
157 - cdef float colour  
158 - cdef float colour_p = 0  
159 -  
160 - cdef int x, y, z  
161 -  
162 - # AXIAL  
163 - if axis == 0:  
164 - for x in prange(sx, nogil=True):  
165 - for y in xrange(sy):  
166 - fmax = 0.0  
167 - alpha_p = 0.0  
168 - colour_p = 0.0  
169 - for z in xrange(sz):  
170 - vl = image[z, y, x]  
171 - fpi = 1.0/(max - min) * (vl - min)  
172 - if fpi > fmax:  
173 - dl = fpi - fmax  
174 - fmax = fpi  
175 - else:  
176 - dl = 0.0  
177 -  
178 - bt = 1.0 - dl  
179 -  
180 - colour = fpi  
181 - alpha = get_opacity(vl, wl, ww)  
182 - colour = (bt * colour_p) + (1 - bt * alpha_p) * colour * alpha  
183 - alpha = (bt * alpha_p) + (1 - bt * alpha_p) * alpha  
184 -  
185 - colour_p = colour  
186 - alpha_p = alpha  
187 -  
188 - if alpha >= 1.0:  
189 - break  
190 -  
191 -  
192 - #out[y, x] = <DTYPE16_t>((max_value - min_value) * colour + min_value)  
193 - out[y, x] = <DTYPE16_t>((max - min) * colour + min)  
194 -  
195 -  
196 - #CORONAL  
197 - elif axis == 1:  
198 - for z in prange(sz, nogil=True):  
199 - for x in xrange(sx):  
200 - fmax = 0.0  
201 - alpha_p = 0.0  
202 - colour_p = 0.0  
203 - for y in xrange(sy):  
204 - vl = image[z, y, x]  
205 - fpi = 1.0/(max - min) * (vl - min)  
206 - if fpi > fmax:  
207 - dl = fpi - fmax  
208 - fmax = fpi  
209 - else:  
210 - dl = 0.0  
211 -  
212 - bt = 1.0 - dl  
213 -  
214 - colour = fpi  
215 - alpha = get_opacity(vl, wl, ww)  
216 - colour = (bt * colour_p) + (1 - bt * alpha_p) * colour * alpha  
217 - alpha = (bt * alpha_p) + (1 - bt * alpha_p) * alpha  
218 -  
219 - colour_p = colour  
220 - alpha_p = alpha  
221 -  
222 - if alpha >= 1.0:  
223 - break  
224 -  
225 - out[z, x] = <DTYPE16_t>((max - min) * colour + min)  
226 -  
227 - #AXIAL  
228 - elif axis == 2:  
229 - for z in prange(sz, nogil=True):  
230 - for y in xrange(sy):  
231 - fmax = 0.0  
232 - alpha_p = 0.0  
233 - colour_p = 0.0  
234 - for x in xrange(sx):  
235 - vl = image[z, y, x]  
236 - fpi = 1.0/(max - min) * (vl - min)  
237 - if fpi > fmax:  
238 - dl = fpi - fmax  
239 - fmax = fpi  
240 - else:  
241 - dl = 0.0  
242 -  
243 - bt = 1.0 - dl  
244 -  
245 - colour = fpi  
246 - alpha = get_opacity(vl, wl, ww)  
247 - colour = (bt * colour_p) + (1 - bt * alpha_p) * colour * alpha  
248 - alpha = (bt * alpha_p) + (1 - bt * alpha_p) * alpha  
249 -  
250 - colour_p = colour  
251 - alpha_p = alpha  
252 -  
253 - if alpha >= 1.0:  
254 - break  
255 -  
256 - out[z, y] = <DTYPE16_t>((max - min) * colour + min)  
257 -  
258 -  
259 -  
260 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
261 -@cython.cdivision(True)  
262 -cdef inline void finite_difference(DTYPE16_t[:, :, :] image,  
263 - int x, int y, int z, float h, float *g) nogil:  
264 - cdef int px, py, pz, fx, fy, fz  
265 -  
266 - cdef int sz = image.shape[0]  
267 - cdef int sy = image.shape[1]  
268 - cdef int sx = image.shape[2]  
269 -  
270 - cdef float gx, gy, gz  
271 -  
272 - if x == 0:  
273 - px = 0  
274 - fx = 1  
275 - elif x == sx - 1:  
276 - px = x - 1  
277 - fx = x  
278 - else:  
279 - px = x - 1  
280 - fx = x + 1  
281 -  
282 - if y == 0:  
283 - py = 0  
284 - fy = 1  
285 - elif y == sy - 1:  
286 - py = y - 1  
287 - fy = y  
288 - else:  
289 - py = y - 1  
290 - fy = y + 1  
291 -  
292 - if z == 0:  
293 - pz = 0  
294 - fz = 1  
295 - elif z == sz - 1:  
296 - pz = z - 1  
297 - fz = z  
298 - else:  
299 - pz = z - 1  
300 - fz = z + 1  
301 -  
302 - gx = (image[z, y, fx] - image[z, y, px]) / (2*h)  
303 - gy = (image[z, fy, x] - image[z, py, x]) / (2*h)  
304 - gz = (image[fz, y, x] - image[pz, y, x]) / (2*h)  
305 -  
306 - g[0] = gx  
307 - g[1] = gy  
308 - g[2] = gz  
309 -  
310 -  
311 -  
312 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
313 -@cython.cdivision(True)  
314 -cdef inline float calc_fcm_itensity(DTYPE16_t[:, :, :] image,  
315 - int x, int y, int z, float n, float* dir) nogil:  
316 - cdef float g[3]  
317 - finite_difference(image, x, y, z, 1.0, g)  
318 - cdef float gm = sqrt(g[0]*g[0] + g[1]*g[1] + g[2]*g[2])  
319 - cdef float d = g[0]*dir[0] + g[1]*dir[1] + g[2]*dir[2]  
320 - cdef float sf = (1.0 - fabs(d/gm))**n  
321 - #alpha = get_opacity_f32(gm, wl, ww)  
322 - cdef float vl = gm * sf  
323 - return vl  
324 -  
325 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
326 -@cython.cdivision(True)  
327 -def fast_countour_mip(np.ndarray[DTYPE16_t, ndim=3] image,  
328 - float n,  
329 - int axis,  
330 - DTYPE16_t wl, DTYPE16_t ww,  
331 - int tmip,  
332 - np.ndarray[DTYPE16_t, ndim=2] out):  
333 - cdef int sz = image.shape[0]  
334 - cdef int sy = image.shape[1]  
335 - cdef int sx = image.shape[2]  
336 - cdef float gm  
337 - cdef float alpha  
338 - cdef float sf  
339 - cdef float d  
340 -  
341 - cdef float* g  
342 - cdef float* dir = [ 0, 0, 0 ]  
343 -  
344 - cdef DTYPE16_t[:, :, :] vimage = image  
345 - cdef np.ndarray[DTYPE16_t, ndim=3] tmp = np.empty_like(image)  
346 -  
347 - cdef DTYPE16_t min = image.min()  
348 - cdef DTYPE16_t max = image.max()  
349 - cdef float fmin = <float>min  
350 - cdef float fmax = <float>max  
351 - cdef float vl  
352 - cdef DTYPE16_t V  
353 -  
354 - cdef int x, y, z  
355 -  
356 - if axis == 0:  
357 - dir[2] = 1.0  
358 - elif axis == 1:  
359 - dir[1] = 1.0  
360 - elif axis == 2:  
361 - dir[0] = 1.0  
362 -  
363 - for z in prange(sz, nogil=True):  
364 - for y in range(sy):  
365 - for x in range(sx):  
366 - vl = calc_fcm_itensity(vimage, x, y, z, n, dir)  
367 - tmp[z, y, x] = <DTYPE16_t>vl  
368 -  
369 - cdef DTYPE16_t tmin = tmp.min()  
370 - cdef DTYPE16_t tmax = tmp.max()  
371 -  
372 - #tmp = ((max - min)/<float>(tmax - tmin)) * (tmp - tmin) + min  
373 -  
374 - if tmip == 0:  
375 - out[:] = tmp.max(axis)  
376 - elif tmip == 1:  
377 - lmip(tmp, axis, 700, 3033, out)  
378 - elif tmip == 2:  
379 - mida(tmp, axis, wl, ww, out)  
invesalius/data/slice_.py
@@ -28,13 +28,13 @@ from wx.lib.pubsub import pub as Publisher @@ -28,13 +28,13 @@ from wx.lib.pubsub import pub as Publisher
28 import invesalius.constants as const 28 import invesalius.constants as const
29 import invesalius.data.converters as converters 29 import invesalius.data.converters as converters
30 import invesalius.data.imagedata_utils as iu 30 import invesalius.data.imagedata_utils as iu
31 -import invesalius.data.transformations as transformations  
32 import invesalius.session as ses 31 import invesalius.session as ses
33 import invesalius.style as st 32 import invesalius.style as st
34 import invesalius.utils as utils 33 import invesalius.utils as utils
35 -from invesalius.data import mips, transforms 34 +from invesalius.data import transformations
36 from invesalius.data.mask import Mask 35 from invesalius.data.mask import Mask
37 from invesalius.project import Project 36 from invesalius.project import Project
  37 +from invesalius_cy import mips, transforms
38 38
39 OTHER = 0 39 OTHER = 0
40 PLIST = 1 40 PLIST = 1
invesalius/data/styles.py
@@ -46,7 +46,7 @@ import invesalius.utils as utils @@ -46,7 +46,7 @@ import invesalius.utils as utils
46 from invesalius.data.measures import (CircleDensityMeasure, MeasureData, 46 from invesalius.data.measures import (CircleDensityMeasure, MeasureData,
47 PolygonDensityMeasure) 47 PolygonDensityMeasure)
48 48
49 -from . import floodfill 49 +from invesalius_cy import floodfill
50 50
51 ORIENTATIONS = { 51 ORIENTATIONS = {
52 "AXIAL": const.AXIAL, 52 "AXIAL": const.AXIAL,
invesalius/data/surface.py
@@ -59,9 +59,9 @@ import invesalius.utils as utl @@ -59,9 +59,9 @@ import invesalius.utils as utl
59 import invesalius.data.vtk_utils as vu 59 import invesalius.data.vtk_utils as vu
60 60
61 from invesalius.gui import dialogs 61 from invesalius.gui import dialogs
  62 +from invesalius_cy import cy_mesh
62 63
63 -from invesalius.data import cy_mesh  
64 -# TODO: Verificar ReleaseDataFlagOn and SetSource 64 +# TODO: Verificar ReleaseDataFlagOn and SetSource
65 65
66 66
67 class Surface(): 67 class Surface():
invesalius/data/surface_process.py
@@ -13,7 +13,7 @@ import vtk @@ -13,7 +13,7 @@ import vtk
13 13
14 import invesalius.i18n as i18n 14 import invesalius.i18n as i18n
15 import invesalius.data.converters as converters 15 import invesalius.data.converters as converters
16 -from invesalius.data import cy_mesh 16 +from invesalius_cy import cy_mesh
17 17
18 import weakref 18 import weakref
19 from scipy import ndimage 19 from scipy import ndimage
invesalius/data/transforms.pyx
@@ -1,174 +0,0 @@ @@ -1,174 +0,0 @@
1 -import numpy as np  
2 -cimport numpy as np  
3 -cimport cython  
4 -  
5 -from .cy_my_types cimport image_t  
6 -from .interpolation cimport interpolate, tricub_interpolate, tricubicInterpolate, lanczos3, nearest_neighbour_interp  
7 -  
8 -from libc.math cimport floor, ceil, sqrt, fabs, round  
9 -from cython.parallel import prange  
10 -  
11 -ctypedef double (*interp_function)(image_t[:, :, :], double, double, double) nogil  
12 -  
13 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
14 -@cython.cdivision(True)  
15 -@cython.wraparound(False)  
16 -cdef void mul_mat4_vec4(double[:, :] M,  
17 - double* coord,  
18 - double* out) nogil:  
19 -  
20 - out[0] = coord[0] * M[0, 0] + coord[1] * M[0, 1] + coord[2] * M[0, 2] + coord[3] * M[0, 3]  
21 - out[1] = coord[0] * M[1, 0] + coord[1] * M[1, 1] + coord[2] * M[1, 2] + coord[3] * M[1, 3]  
22 - out[2] = coord[0] * M[2, 0] + coord[1] * M[2, 1] + coord[2] * M[2, 2] + coord[3] * M[2, 3]  
23 - out[3] = coord[0] * M[3, 0] + coord[1] * M[3, 1] + coord[2] * M[3, 2] + coord[3] * M[3, 3]  
24 -  
25 -  
26 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
27 -@cython.cdivision(True)  
28 -@cython.wraparound(False)  
29 -cdef image_t coord_transform(image_t[:, :, :] volume, double[:, :] M, int x, int y, int z, double sx, double sy, double sz, interp_function f_interp, image_t cval) nogil:  
30 -  
31 - cdef double coord[4]  
32 - coord[0] = z*sz  
33 - coord[1] = y*sy  
34 - coord[2] = x*sx  
35 - coord[3] = 1.0  
36 -  
37 - cdef double _ncoord[4]  
38 - _ncoord[3] = 1  
39 - # _ncoord[:] = [0.0, 0.0, 0.0, 1.0]  
40 -  
41 - cdef unsigned int dz, dy, dx  
42 - dz = volume.shape[0]  
43 - dy = volume.shape[1]  
44 - dx = volume.shape[2]  
45 -  
46 -  
47 - mul_mat4_vec4(M, coord, _ncoord)  
48 -  
49 - cdef double nz, ny, nx  
50 - nz = (_ncoord[0]/_ncoord[3])/sz  
51 - ny = (_ncoord[1]/_ncoord[3])/sy  
52 - nx = (_ncoord[2]/_ncoord[3])/sx  
53 -  
54 - cdef double v  
55 -  
56 - if 0 <= nz <= (dz-1) and 0 <= ny <= (dy-1) and 0 <= nx <= (dx-1):  
57 - return <image_t>f_interp(volume, nx, ny, nz)  
58 - # if minterpol == 0:  
59 - # return <image_t>nearest_neighbour_interp(volume, nx, ny, nz)  
60 - # elif minterpol == 1:  
61 - # return <image_t>interpolate(volume, nx, ny, nz)  
62 - # elif minterpol == 2:  
63 - # v = tricubicInterpolate(volume, nx, ny, nz)  
64 - # if (v < cval):  
65 - # v = cval  
66 - # return <image_t>v  
67 - # else:  
68 - # v = lanczos3(volume, nx, ny, nz)  
69 - # if (v < cval):  
70 - # v = cval  
71 - # return <image_t>v  
72 - else:  
73 - return cval  
74 -  
75 -  
76 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
77 -@cython.cdivision(True)  
78 -@cython.wraparound(False)  
79 -def apply_view_matrix_transform(image_t[:, :, :] volume,  
80 - spacing,  
81 - double[:, :] M,  
82 - unsigned int n, str orientation,  
83 - int minterpol,  
84 - image_t cval,  
85 - image_t[:, :, :] out):  
86 -  
87 - cdef int dz, dy, dx  
88 - cdef int z, y, x  
89 - dz = volume.shape[0]  
90 - dy = volume.shape[1]  
91 - dx = volume.shape[2]  
92 -  
93 - cdef unsigned int odz, ody, odx  
94 - odz = out.shape[0]  
95 - ody = out.shape[1]  
96 - odx = out.shape[2]  
97 -  
98 - cdef unsigned int count = 0  
99 -  
100 - cdef double sx, sy, sz  
101 - sx = spacing[0]  
102 - sy = spacing[1]  
103 - sz = spacing[2]  
104 -  
105 - cdef interp_function f_interp  
106 -  
107 - if minterpol == 0:  
108 - f_interp = nearest_neighbour_interp  
109 - elif minterpol == 1:  
110 - f_interp = interpolate  
111 - elif minterpol == 2:  
112 - f_interp = tricubicInterpolate  
113 - else:  
114 - f_interp = lanczos3  
115 -  
116 - if orientation == 'AXIAL':  
117 - for z in xrange(n, n+odz):  
118 - for y in prange(dy, nogil=True):  
119 - for x in xrange(dx):  
120 - out[count, y, x] = coord_transform(volume, M, x, y, z, sx, sy, sz, f_interp, cval)  
121 - count += 1  
122 -  
123 - elif orientation == 'CORONAL':  
124 - for y in xrange(n, n+ody):  
125 - for z in prange(dz, nogil=True):  
126 - for x in xrange(dx):  
127 - out[z, count, x] = coord_transform(volume, M, x, y, z, sx, sy, sz, f_interp, cval)  
128 - count += 1  
129 -  
130 - elif orientation == 'SAGITAL':  
131 - for x in xrange(n, n+odx):  
132 - for z in prange(dz, nogil=True):  
133 - for y in xrange(dy):  
134 - out[z, y, count] = coord_transform(volume, M, x, y, z, sx, sy, sz, f_interp, cval)  
135 - count += 1  
136 -  
137 -  
138 -@cython.boundscheck(False) # turn of bounds-checking for entire function  
139 -@cython.cdivision(True)  
140 -@cython.wraparound(False)  
141 -def convolve_non_zero(image_t[:, :, :] volume,  
142 - image_t[:, :, :] kernel,  
143 - image_t cval):  
144 - cdef Py_ssize_t x, y, z, sx, sy, sz, kx, ky, kz, skx, sky, skz, i, j, k  
145 - cdef image_t v  
146 -  
147 - cdef image_t[:, :, :] out = np.zeros_like(volume)  
148 -  
149 - sz = volume.shape[0]  
150 - sy = volume.shape[1]  
151 - sx = volume.shape[2]  
152 -  
153 - skz = kernel.shape[0]  
154 - sky = kernel.shape[1]  
155 - skx = kernel.shape[2]  
156 -  
157 - for z in prange(sz, nogil=True):  
158 - for y in xrange(sy):  
159 - for x in xrange(sx):  
160 - if volume[z, y, x] != 0:  
161 - for k in xrange(skz):  
162 - kz = z - skz // 2 + k  
163 - for j in xrange(sky):  
164 - ky = y - sky // 2 + j  
165 - for i in xrange(skx):  
166 - kx = x - skx // 2 + i  
167 -  
168 - if 0 <= kz < sz and 0 <= ky < sy and 0 <= kx < sx:  
169 - v = volume[kz, ky, kx]  
170 - else:  
171 - v = cval  
172 -  
173 - out[z, y, x] += (v * kernel[k, j, i])  
174 - return np.asarray(out)  
invesalius_cy/cy_mesh.pyx 0 → 100644
@@ -0,0 +1,466 @@ @@ -0,0 +1,466 @@
  1 +# distutils: language = c++
  2 +#cython: boundscheck=False
  3 +#cython: wraparound=False
  4 +#cython: initializedcheck=False
  5 +#cython: cdivision=True
  6 +#cython: nonecheck=False
  7 +
  8 +import sys
  9 +import time
  10 +cimport numpy as np
  11 +
  12 +from libc.math cimport sin, cos, acos, exp, sqrt, fabs, M_PI
  13 +from libc.stdlib cimport abs as cabs
  14 +from cython.operator cimport dereference as deref, preincrement as inc
  15 +from libcpp.map cimport map
  16 +from libcpp.unordered_map cimport unordered_map
  17 +from libcpp.set cimport set
  18 +from libcpp.vector cimport vector
  19 +from libcpp.pair cimport pair
  20 +from libcpp cimport bool
  21 +from libcpp.deque cimport deque as cdeque
  22 +from cython.parallel import prange
  23 +
  24 +from cy_my_types cimport vertex_t, normal_t, vertex_id_t
  25 +
  26 +import numpy as np
  27 +import vtk
  28 +
  29 +from vtk.util import numpy_support
  30 +
  31 +ctypedef float weight_t
  32 +
  33 +cdef struct Point:
  34 + vertex_t x
  35 + vertex_t y
  36 + vertex_t z
  37 +
  38 +ctypedef pair[vertex_id_t, vertex_id_t] key
  39 +
  40 +
  41 +cdef class Mesh:
  42 + cdef vertex_t[:, :] vertices
  43 + cdef vertex_id_t[:, :] faces
  44 + cdef normal_t[:, :] normals
  45 +
  46 + cdef unordered_map[int, vector[vertex_id_t]] map_vface
  47 + cdef unordered_map[vertex_id_t, int] border_vertices
  48 +
  49 + cdef bool _initialized
  50 +
  51 + def __cinit__(self, pd=None, other=None):
  52 + cdef int i
  53 + cdef map[key, int] edge_nfaces
  54 + cdef map[key, int].iterator it
  55 + if pd:
  56 + self._initialized = True
  57 + _vertices = numpy_support.vtk_to_numpy(pd.GetPoints().GetData())
  58 + _vertices.shape = -1, 3
  59 +
  60 + _faces = numpy_support.vtk_to_numpy(pd.GetPolys().GetData())
  61 + _faces.shape = -1, 4
  62 +
  63 + _normals = numpy_support.vtk_to_numpy(pd.GetCellData().GetArray("Normals"))
  64 + _normals.shape = -1, 3
  65 +
  66 + self.vertices = _vertices
  67 + self.faces = _faces
  68 + self.normals = _normals
  69 +
  70 + for i in xrange(_faces.shape[0]):
  71 + self.map_vface[self.faces[i, 1]].push_back(i)
  72 + self.map_vface[self.faces[i, 2]].push_back(i)
  73 + self.map_vface[self.faces[i, 3]].push_back(i)
  74 +
  75 + edge_nfaces[key(min(self.faces[i, 1], self.faces[i, 2]), max(self.faces[i, 1], self.faces[i, 2]))] += 1
  76 + edge_nfaces[key(min(self.faces[i, 2], self.faces[i, 3]), max(self.faces[i, 2], self.faces[i, 3]))] += 1
  77 + edge_nfaces[key(min(self.faces[i, 1], self.faces[i, 3]), max(self.faces[i, 1], self.faces[i, 3]))] += 1
  78 +
  79 + it = edge_nfaces.begin()
  80 +
  81 + while it != edge_nfaces.end():
  82 + if deref(it).second == 1:
  83 + self.border_vertices[deref(it).first.first] = 1
  84 + self.border_vertices[deref(it).first.second] = 1
  85 +
  86 + inc(it)
  87 +
  88 + elif other:
  89 + _other = <Mesh>other
  90 + self._initialized = True
  91 + self.vertices = _other.vertices.copy()
  92 + self.faces = _other.faces.copy()
  93 + self.normals = _other.normals.copy()
  94 + self.map_vface = unordered_map[int, vector[vertex_id_t]](_other.map_vface)
  95 + self.border_vertices = unordered_map[vertex_id_t, int](_other.border_vertices)
  96 + else:
  97 + self._initialized = False
  98 +
  99 + cdef void copy_to(self, Mesh other):
  100 + """
  101 + Copies self content to other.
  102 + """
  103 + if self._initialized:
  104 + other.vertices[:] = self.vertices
  105 + other.faces[:] = self.faces
  106 + other.normals[:] = self.normals
  107 + other.map_vface = unordered_map[int, vector[vertex_id_t]](self.map_vface)
  108 + other.border_vertices = unordered_map[vertex_id_t, int](self.border_vertices)
  109 + else:
  110 + other.vertices = self.vertices.copy()
  111 + other.faces = self.faces.copy()
  112 + other.normals = self.normals.copy()
  113 +
  114 + other.map_vface = self.map_vface
  115 + other.border_vertices = self.border_vertices
  116 +
  117 + def to_vtk(self):
  118 + """
  119 + Converts Mesh to vtkPolyData.
  120 + """
  121 + vertices = np.asarray(self.vertices)
  122 + faces = np.asarray(self.faces)
  123 + normals = np.asarray(self.normals)
  124 +
  125 + points = vtk.vtkPoints()
  126 + points.SetData(numpy_support.numpy_to_vtk(vertices))
  127 +
  128 + id_triangles = numpy_support.numpy_to_vtkIdTypeArray(faces)
  129 + triangles = vtk.vtkCellArray()
  130 + triangles.SetCells(faces.shape[0], id_triangles)
  131 +
  132 + pd = vtk.vtkPolyData()
  133 + pd.SetPoints(points)
  134 + pd.SetPolys(triangles)
  135 +
  136 + return pd
  137 +
  138 + cdef vector[vertex_id_t]* get_faces_by_vertex(self, int v_id) nogil:
  139 + """
  140 + Returns the faces whose vertex `v_id' is part.
  141 + """
  142 + return &self.map_vface[v_id]
  143 +
  144 + cdef set[vertex_id_t]* get_ring1(self, vertex_id_t v_id) nogil:
  145 + """
  146 + Returns the ring1 of vertex `v_id'
  147 + """
  148 + cdef vertex_id_t f_id
  149 + cdef set[vertex_id_t]* ring1 = new set[vertex_id_t]()
  150 + cdef vector[vertex_id_t].iterator it = self.map_vface[v_id].begin()
  151 +
  152 + while it != self.map_vface[v_id].end():
  153 + f_id = deref(it)
  154 + inc(it)
  155 + if self.faces[f_id, 1] != v_id:
  156 + ring1.insert(self.faces[f_id, 1])
  157 + if self.faces[f_id, 2] != v_id:
  158 + ring1.insert(self.faces[f_id, 2])
  159 + if self.faces[f_id, 3] != v_id:
  160 + ring1.insert(self.faces[f_id, 3])
  161 +
  162 + return ring1
  163 +
  164 + cdef bool is_border(self, vertex_id_t v_id) nogil:
  165 + """
  166 + Check if vertex `v_id' is a vertex border.
  167 + """
  168 + return self.border_vertices.find(v_id) != self.border_vertices.end()
  169 +
  170 + cdef vector[vertex_id_t]* get_near_vertices_to_v(self, vertex_id_t v_id, float dmax) nogil:
  171 + """
  172 + Returns all vertices with distance at most `d' to the vertex `v_id'
  173 +
  174 + Params:
  175 + v_id: id of the vertex
  176 + dmax: the maximum distance.
  177 + """
  178 + cdef vector[vertex_id_t]* idfaces
  179 + cdef vector[vertex_id_t]* near_vertices = new vector[vertex_id_t]()
  180 +
  181 + cdef cdeque[vertex_id_t] to_visit
  182 + cdef unordered_map[vertex_id_t, bool] status_v
  183 + cdef unordered_map[vertex_id_t, bool] status_f
  184 +
  185 + cdef vertex_t *vip
  186 + cdef vertex_t *vjp
  187 +
  188 + cdef float distance
  189 + cdef int nf, nid, j
  190 + cdef vertex_id_t f_id, vj
  191 +
  192 + vip = &self.vertices[v_id, 0]
  193 + to_visit.push_back(v_id)
  194 + while(not to_visit.empty()):
  195 + v_id = to_visit.front()
  196 + to_visit.pop_front()
  197 +
  198 + status_v[v_id] = True
  199 +
  200 + idfaces = self.get_faces_by_vertex(v_id)
  201 + nf = idfaces.size()
  202 +
  203 + for nid in xrange(nf):
  204 + f_id = deref(idfaces)[nid]
  205 + if status_f.find(f_id) == status_f.end():
  206 + status_f[f_id] = True
  207 +
  208 + for j in xrange(3):
  209 + vj = self.faces[f_id, j+1]
  210 + if status_v.find(vj) == status_v.end():
  211 + status_v[vj] = True
  212 + vjp = &self.vertices[vj, 0]
  213 + distance = sqrt((vip[0] - vjp[0]) * (vip[0] - vjp[0]) \
  214 + + (vip[1] - vjp[1]) * (vip[1] - vjp[1]) \
  215 + + (vip[2] - vjp[2]) * (vip[2] - vjp[2]))
  216 + if distance <= dmax:
  217 + near_vertices.push_back(vj)
  218 + to_visit.push_back(vj)
  219 +
  220 + return near_vertices
  221 +
  222 +
  223 +cdef vector[weight_t]* calc_artifacts_weight(Mesh mesh, vector[vertex_id_t]& vertices_staircase, float tmax, float bmin) nogil:
  224 + """
  225 + Calculate the artifact weight based on distance of each vertex to its
  226 + nearest staircase artifact vertex.
  227 +
  228 + Params:
  229 + mesh: Mesh
  230 + vertices_staircase: the identified staircase artifact vertices
  231 + tmax: max distance the vertex must be to its nearest artifact vertex
  232 + to considered to calculate the weight
  233 + bmin: The minimum weight.
  234 + """
  235 + cdef int vi_id, vj_id, nnv, n_ids, i, j
  236 + cdef vector[vertex_id_t]* near_vertices
  237 + cdef weight_t value
  238 + cdef float d
  239 + n_ids = vertices_staircase.size()
  240 +
  241 + cdef vertex_t* vi
  242 + cdef vertex_t* vj
  243 + cdef size_t msize
  244 +
  245 + msize = mesh.vertices.shape[0]
  246 + cdef vector[weight_t]* weights = new vector[weight_t](msize)
  247 + weights.assign(msize, bmin)
  248 +
  249 + for i in prange(n_ids, nogil=True):
  250 + vi_id = vertices_staircase[i]
  251 + deref(weights)[vi_id] = 1.0
  252 +
  253 + vi = &mesh.vertices[vi_id, 0]
  254 + near_vertices = mesh.get_near_vertices_to_v(vi_id, tmax)
  255 + nnv = near_vertices.size()
  256 +
  257 + for j in xrange(nnv):
  258 + vj_id = deref(near_vertices)[j]
  259 + vj = &mesh.vertices[vj_id, 0]
  260 +
  261 + d = sqrt((vi[0] - vj[0]) * (vi[0] - vj[0])\
  262 + + (vi[1] - vj[1]) * (vi[1] - vj[1])\
  263 + + (vi[2] - vj[2]) * (vi[2] - vj[2]))
  264 + value = (1.0 - d/tmax) * (1.0 - bmin) + bmin
  265 +
  266 + if value > deref(weights)[vj_id]:
  267 + deref(weights)[vj_id] = value
  268 +
  269 + del near_vertices
  270 +
  271 + # for i in xrange(msize):
  272 + # if mesh.is_border(i):
  273 + # deref(weights)[i] = 0.0
  274 +
  275 + # cdef vertex_id_t v0, v1, v2
  276 + # for i in xrange(mesh.faces.shape[0]):
  277 + # for j in xrange(1, 4):
  278 + # v0 = mesh.faces[i, j]
  279 + # vi = &mesh.vertices[v0, 0]
  280 + # if mesh.is_border(v0):
  281 + # deref(weights)[v0] = 0.0
  282 + # v1 = mesh.faces[i, (j + 1) % 3 + 1]
  283 + # if mesh.is_border(v1):
  284 + # vi = &mesh.vertices[v1, 0]
  285 + # deref(weights)[v0] = 0.0
  286 +
  287 + return weights
  288 +
  289 +
  290 +cdef inline Point calc_d(Mesh mesh, vertex_id_t v_id) nogil:
  291 + cdef Point D
  292 + cdef int nf, f_id, nid
  293 + cdef float n=0
  294 + cdef int i
  295 + cdef vertex_t* vi
  296 + cdef vertex_t* vj
  297 + cdef set[vertex_id_t]* vertices
  298 + cdef set[vertex_id_t].iterator it
  299 + cdef vertex_id_t vj_id
  300 +
  301 + D.x = 0.0
  302 + D.y = 0.0
  303 + D.z = 0.0
  304 +
  305 + vertices = mesh.get_ring1(v_id)
  306 + vi = &mesh.vertices[v_id, 0]
  307 +
  308 + if mesh.is_border(v_id):
  309 + it = vertices.begin()
  310 + while it != vertices.end():
  311 + vj_id = deref(it)
  312 + if mesh.is_border(vj_id):
  313 + vj = &mesh.vertices[vj_id, 0]
  314 +
  315 + D.x = D.x + (vi[0] - vj[0])
  316 + D.y = D.y + (vi[1] - vj[1])
  317 + D.z = D.z + (vi[2] - vj[2])
  318 + n += 1.0
  319 +
  320 + inc(it)
  321 + else:
  322 + it = vertices.begin()
  323 + while it != vertices.end():
  324 + vj_id = deref(it)
  325 + vj = &mesh.vertices[vj_id, 0]
  326 +
  327 + D.x = D.x + (vi[0] - vj[0])
  328 + D.y = D.y + (vi[1] - vj[1])
  329 + D.z = D.z + (vi[2] - vj[2])
  330 + n += 1.0
  331 +
  332 + inc(it)
  333 +
  334 + del vertices
  335 +
  336 + D.x = D.x / n
  337 + D.y = D.y / n
  338 + D.z = D.z / n
  339 + return D
  340 +
  341 +cdef vector[vertex_id_t]* find_staircase_artifacts(Mesh mesh, double[3] stack_orientation, double T) nogil:
  342 + """
  343 + This function is used to find vertices at staircase artifacts, which are
  344 + those vertices whose incident faces' orientation differences are
  345 + greater than T.
  346 +
  347 + Params:
  348 + mesh: Mesh
  349 + stack_orientation: orientation of slice stacking
  350 + T: Min angle (between vertex faces and stack_orientation) to consider a
  351 + vertex a staircase artifact.
  352 + """
  353 + cdef int nv, nf, f_id, v_id
  354 + cdef double of_z, of_y, of_x, min_z, max_z, min_y, max_y, min_x, max_x;
  355 + cdef vector[vertex_id_t]* f_ids
  356 + cdef normal_t* normal
  357 +
  358 + cdef vector[vertex_id_t]* output = new vector[vertex_id_t]()
  359 + cdef int i
  360 +
  361 + nv = mesh.vertices.shape[0]
  362 +
  363 + for v_id in xrange(nv):
  364 + max_z = -10000
  365 + min_z = 10000
  366 + max_y = -10000
  367 + min_y = 10000
  368 + max_x = -10000
  369 + min_x = 10000
  370 +
  371 + f_ids = mesh.get_faces_by_vertex(v_id)
  372 + nf = deref(f_ids).size()
  373 +
  374 + for i in xrange(nf):
  375 + f_id = deref(f_ids)[i]
  376 + normal = &mesh.normals[f_id, 0]
  377 +
  378 + of_z = 1 - fabs(normal[0]*stack_orientation[0] + normal[1]*stack_orientation[1] + normal[2]*stack_orientation[2]);
  379 + of_y = 1 - fabs(normal[0]*0 + normal[1]*1 + normal[2]*0);
  380 + of_x = 1 - fabs(normal[0]*1 + normal[1]*0 + normal[2]*0);
  381 +
  382 + if (of_z > max_z):
  383 + max_z = of_z
  384 +
  385 + if (of_z < min_z):
  386 + min_z = of_z
  387 +
  388 + if (of_y > max_y):
  389 + max_y = of_y
  390 +
  391 + if (of_y < min_y):
  392 + min_y = of_y
  393 +
  394 + if (of_x > max_x):
  395 + max_x = of_x
  396 +
  397 + if (of_x < min_x):
  398 + min_x = of_x
  399 +
  400 +
  401 + if ((fabs(max_z - min_z) >= T) or (fabs(max_y - min_y) >= T) or (fabs(max_x - min_x) >= T)):
  402 + output.push_back(v_id)
  403 + break
  404 + return output
  405 +
  406 +
  407 +cdef void taubin_smooth(Mesh mesh, vector[weight_t]& weights, float l, float m, int steps):
  408 + """
  409 + Implementation of Taubin's smooth algorithm described in the paper "A
  410 + Signal Processing Approach To Fair Surface Design". His benefeat is it
  411 + avoids surface shrinking.
  412 + """
  413 + cdef int s, i, nvertices
  414 + nvertices = mesh.vertices.shape[0]
  415 + cdef vector[Point] D = vector[Point](nvertices)
  416 + cdef vertex_t* vi
  417 + for s in xrange(steps):
  418 + for i in prange(nvertices, nogil=True):
  419 + D[i] = calc_d(mesh, i)
  420 +
  421 + for i in prange(nvertices, nogil=True):
  422 + mesh.vertices[i, 0] += weights[i]*l*D[i].x;
  423 + mesh.vertices[i, 1] += weights[i]*l*D[i].y;
  424 + mesh.vertices[i, 2] += weights[i]*l*D[i].z;
  425 +
  426 + for i in prange(nvertices, nogil=True):
  427 + D[i] = calc_d(mesh, i)
  428 +
  429 + for i in prange(nvertices, nogil=True):
  430 + mesh.vertices[i, 0] += weights[i]*m*D[i].x;
  431 + mesh.vertices[i, 1] += weights[i]*m*D[i].y;
  432 + mesh.vertices[i, 2] += weights[i]*m*D[i].z;
  433 +
  434 +
  435 +def ca_smoothing(Mesh mesh, double T, double tmax, double bmin, int n_iters):
  436 + """
  437 + This is a implementation of the paper "Context-aware mesh smoothing for
  438 + biomedical applications". It can be used to smooth meshes generated by
  439 + binary images to remove its staircase artifacts and keep the fine features.
  440 +
  441 + Params:
  442 + mesh: Mesh
  443 + T: Min angle (between vertex faces and stack_orientation) to consider a
  444 + vertex a staircase artifact
  445 + tmax: max distance the vertex must be to its nearest artifact vertex
  446 + to considered to calculate the weight
  447 + bmin: The minimum weight
  448 + n_iters: Number of iterations.
  449 + """
  450 + cdef double[3] stack_orientation = [0.0, 0.0, 1.0]
  451 +
  452 + t0 = time.time()
  453 + cdef vector[vertex_id_t]* vertices_staircase = find_staircase_artifacts(mesh, stack_orientation, T)
  454 + print "vertices staircase", time.time() - t0
  455 +
  456 + t0 = time.time()
  457 + cdef vector[weight_t]* weights = calc_artifacts_weight(mesh, deref(vertices_staircase), tmax, bmin)
  458 + print "Weights", time.time() - t0
  459 +
  460 + del vertices_staircase
  461 +
  462 + t0 = time.time()
  463 + taubin_smooth(mesh, deref(weights), 0.5, -0.53, n_iters)
  464 + print "taubin", time.time() - t0
  465 +
  466 + del weights
invesalius_cy/cy_my_types.pxd 0 → 100644
@@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
  1 +import numpy as np
  2 +cimport numpy as np
  3 +cimport cython
  4 +
  5 +# ctypedef np.uint16_t image_t
  6 +
  7 +ctypedef fused image_t:
  8 + np.float64_t
  9 + np.int16_t
  10 + np.uint8_t
  11 +
  12 +ctypedef np.uint8_t mask_t
  13 +
  14 +ctypedef np.float32_t vertex_t
  15 +ctypedef np.float32_t normal_t
  16 +
  17 +# To compile in windows 64
  18 +IF UNAME_MACHINE == 'AMD64':
  19 + ctypedef np.int64_t vertex_id_t
  20 +ELSE:
  21 + ctypedef np.int_t vertex_id_t
invesalius_cy/floodfill.pyx 0 → 100644
@@ -0,0 +1,274 @@ @@ -0,0 +1,274 @@
  1 +import numpy as np
  2 +cimport numpy as np
  3 +cimport cython
  4 +
  5 +from collections import deque
  6 +
  7 +from cython.parallel import prange
  8 +from libc.math cimport floor, ceil
  9 +from libcpp cimport bool
  10 +from libcpp.deque cimport deque as cdeque
  11 +from libcpp.vector cimport vector
  12 +
  13 +from cy_my_types cimport image_t, mask_t
  14 +
  15 +cdef struct s_coord:
  16 + int x
  17 + int y
  18 + int z
  19 +
  20 +ctypedef s_coord coord
  21 +
  22 +
  23 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  24 +@cython.wraparound(False)
  25 +@cython.nonecheck(False)
  26 +@cython.cdivision(True)
  27 +cdef inline void append_queue(cdeque[int]& stack, int x, int y, int z, int d, int h, int w) nogil:
  28 + stack.push_back(z*h*w + y*w + x)
  29 +
  30 +
  31 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  32 +@cython.wraparound(False)
  33 +@cython.nonecheck(False)
  34 +@cython.cdivision(True)
  35 +cdef inline void pop_queue(cdeque[int]& stack, int* x, int* y, int* z, int d, int h, int w) nogil:
  36 + cdef int i = stack.front()
  37 + stack.pop_front()
  38 + x[0] = i % w
  39 + y[0] = (i / w) % h
  40 + z[0] = i / (h * w)
  41 +
  42 +
  43 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  44 +def floodfill(np.ndarray[image_t, ndim=3] data, int i, int j, int k, int v, int fill, np.ndarray[mask_t, ndim=3] out):
  45 +
  46 + cdef int to_return = 0
  47 + if out is None:
  48 + out = np.zeros_like(data)
  49 + to_return = 1
  50 +
  51 + cdef int x, y, z
  52 + cdef int w, h, d
  53 +
  54 + d = data.shape[0]
  55 + h = data.shape[1]
  56 + w = data.shape[2]
  57 +
  58 + stack = [(i, j, k), ]
  59 + out[k, j, i] = fill
  60 +
  61 + while stack:
  62 + x, y, z = stack.pop()
  63 +
  64 + if z + 1 < d and data[z + 1, y, x] == v and out[z + 1, y, x] != fill:
  65 + out[z + 1, y, x] = fill
  66 + stack.append((x, y, z + 1))
  67 +
  68 + if z - 1 >= 0 and data[z - 1, y, x] == v and out[z - 1, y, x] != fill:
  69 + out[z - 1, y, x] = fill
  70 + stack.append((x, y, z - 1))
  71 +
  72 + if y + 1 < h and data[z, y + 1, x] == v and out[z, y + 1, x] != fill:
  73 + out[z, y + 1, x] = fill
  74 + stack.append((x, y + 1, z))
  75 +
  76 + if y - 1 >= 0 and data[z, y - 1, x] == v and out[z, y - 1, x] != fill:
  77 + out[z, y - 1, x] = fill
  78 + stack.append((x, y - 1, z))
  79 +
  80 + if x + 1 < w and data[z, y, x + 1] == v and out[z, y, x + 1] != fill:
  81 + out[z, y, x + 1] = fill
  82 + stack.append((x + 1, y, z))
  83 +
  84 + if x - 1 >= 0 and data[z, y, x - 1] == v and out[z, y, x - 1] != fill:
  85 + out[z, y, x - 1] = fill
  86 + stack.append((x - 1, y, z))
  87 +
  88 + if to_return:
  89 + return out
  90 +
  91 +
  92 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  93 +@cython.wraparound(False)
  94 +@cython.nonecheck(False)
  95 +def floodfill_threshold(np.ndarray[image_t, ndim=3] data, list seeds, int t0, int t1, int fill, np.ndarray[mask_t, ndim=3] strct, np.ndarray[mask_t, ndim=3] out):
  96 +
  97 + cdef int to_return = 0
  98 + if out is None:
  99 + out = np.zeros_like(data)
  100 + to_return = 1
  101 +
  102 + cdef int x, y, z
  103 + cdef int dx, dy, dz
  104 + cdef int odx, ody, odz
  105 + cdef int xo, yo, zo
  106 + cdef int i, j, k
  107 + cdef int offset_x, offset_y, offset_z
  108 +
  109 + dz = data.shape[0]
  110 + dy = data.shape[1]
  111 + dx = data.shape[2]
  112 +
  113 + odz = strct.shape[0]
  114 + ody = strct.shape[1]
  115 + odx = strct.shape[2]
  116 +
  117 + cdef cdeque[coord] stack
  118 + cdef coord c
  119 +
  120 + offset_z = odz / 2
  121 + offset_y = ody / 2
  122 + offset_x = odx / 2
  123 +
  124 + for i, j, k in seeds:
  125 + if data[k, j, i] >= t0 and data[k, j, i] <= t1:
  126 + c.x = i
  127 + c.y = j
  128 + c.z = k
  129 + stack.push_back(c)
  130 + out[k, j, i] = fill
  131 +
  132 + with nogil:
  133 + while stack.size():
  134 + c = stack.back()
  135 + stack.pop_back()
  136 +
  137 + x = c.x
  138 + y = c.y
  139 + z = c.z
  140 +
  141 + out[z, y, x] = fill
  142 +
  143 + for k in xrange(odz):
  144 + zo = z + k - offset_z
  145 + for j in xrange(ody):
  146 + yo = y + j - offset_y
  147 + for i in xrange(odx):
  148 + if strct[k, j, i]:
  149 + xo = x + i - offset_x
  150 + if 0 <= xo < dx and 0 <= yo < dy and 0 <= zo < dz and out[zo, yo, xo] != fill and t0 <= data[zo, yo, xo] <= t1:
  151 + out[zo, yo, xo] = fill
  152 + c.x = xo
  153 + c.y = yo
  154 + c.z = zo
  155 + stack.push_back(c)
  156 +
  157 + if to_return:
  158 + return out
  159 +
  160 +
  161 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  162 +@cython.wraparound(False)
  163 +@cython.nonecheck(False)
  164 +def floodfill_auto_threshold(np.ndarray[image_t, ndim=3] data, list seeds, float p, int fill, np.ndarray[mask_t, ndim=3] out):
  165 +
  166 + cdef int to_return = 0
  167 + if out is None:
  168 + out = np.zeros_like(data)
  169 + to_return = 1
  170 +
  171 + cdef cdeque[int] stack
  172 + cdef int x, y, z
  173 + cdef int w, h, d
  174 + cdef int xo, yo, zo
  175 + cdef int t0, t1
  176 +
  177 + cdef int i, j, k
  178 +
  179 + d = data.shape[0]
  180 + h = data.shape[1]
  181 + w = data.shape[2]
  182 +
  183 +
  184 + # stack = deque()
  185 +
  186 + x = 0
  187 + y = 0
  188 + z = 0
  189 +
  190 +
  191 + for i, j, k in seeds:
  192 + append_queue(stack, i, j, k, d, h, w)
  193 + out[k, j, i] = fill
  194 + print i, j, k, d, h, w
  195 +
  196 + with nogil:
  197 + while stack.size():
  198 + pop_queue(stack, &x, &y, &z, d, h, w)
  199 +
  200 + # print x, y, z, d, h, w
  201 +
  202 + xo = x
  203 + yo = y
  204 + zo = z
  205 +
  206 + t0 = <int>ceil(data[z, y, x] * (1 - p))
  207 + t1 = <int>floor(data[z, y, x] * (1 + p))
  208 +
  209 + if z + 1 < d and data[z + 1, y, x] >= t0 and data[z + 1, y, x] <= t1 and out[zo + 1, yo, xo] != fill:
  210 + out[zo + 1, yo, xo] = fill
  211 + append_queue(stack, x, y, z+1, d, h, w)
  212 +
  213 + if z - 1 >= 0 and data[z - 1, y, x] >= t0 and data[z - 1, y, x] <= t1 and out[zo - 1, yo, xo] != fill:
  214 + out[zo - 1, yo, xo] = fill
  215 + append_queue(stack, x, y, z-1, d, h, w)
  216 +
  217 + if y + 1 < h and data[z, y + 1, x] >= t0 and data[z, y + 1, x] <= t1 and out[zo, yo + 1, xo] != fill:
  218 + out[zo, yo + 1, xo] = fill
  219 + append_queue(stack, x, y+1, z, d, h, w)
  220 +
  221 + if y - 1 >= 0 and data[z, y - 1, x] >= t0 and data[z, y - 1, x] <= t1 and out[zo, yo - 1, xo] != fill:
  222 + out[zo, yo - 1, xo] = fill
  223 + append_queue(stack, x, y-1, z, d, h, w)
  224 +
  225 + if x + 1 < w and data[z, y, x + 1] >= t0 and data[z, y, x + 1] <= t1 and out[zo, yo, xo + 1] != fill:
  226 + out[zo, yo, xo + 1] = fill
  227 + append_queue(stack, x+1, y, z, d, h, w)
  228 +
  229 + if x - 1 >= 0 and data[z, y, x - 1] >= t0 and data[z, y, x - 1] <= t1 and out[zo, yo, xo - 1] != fill:
  230 + out[zo, yo, xo - 1] = fill
  231 + append_queue(stack, x-1, y, z, d, h, w)
  232 +
  233 + if to_return:
  234 + return out
  235 +
  236 +
  237 +@cython.boundscheck(False)
  238 +@cython.wraparound(False)
  239 +@cython.nonecheck(False)
  240 +def fill_holes_automatically(np.ndarray[mask_t, ndim=3] mask, np.ndarray[np.uint16_t, ndim=3] labels, unsigned int nlabels, unsigned int max_size):
  241 + """
  242 + Fill mask holes automatically. The hole must <= max_size. Return True if any hole were filled.
  243 + """
  244 + cdef np.ndarray[np.uint32_t, ndim=1] sizes = np.zeros(shape=(nlabels + 1), dtype=np.uint32)
  245 + cdef int x, y, z
  246 + cdef int dx, dy, dz
  247 + cdef int i
  248 +
  249 + cdef bool modified = False
  250 +
  251 + dz = mask.shape[0]
  252 + dy = mask.shape[1]
  253 + dx = mask.shape[2]
  254 +
  255 + for z in xrange(dz):
  256 + for y in xrange(dy):
  257 + for x in xrange(dx):
  258 + sizes[labels[z, y, x]] += 1
  259 +
  260 + #Checking if any hole will be filled
  261 + for i in xrange(nlabels + 1):
  262 + if sizes[i] <= max_size:
  263 + modified = True
  264 +
  265 + if not modified:
  266 + return 0
  267 +
  268 + for z in prange(dz, nogil=True):
  269 + for y in xrange(dy):
  270 + for x in xrange(dx):
  271 + if sizes[labels[z, y, x]] <= max_size:
  272 + mask[z, y, x] = 254
  273 +
  274 + return modified
invesalius_cy/interpolation.pxd 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +from .cy_my_types cimport image_t
  2 +
  3 +cdef double interpolate(image_t[:, :, :], double, double, double) nogil
  4 +cdef double tricub_interpolate(image_t[:, :, :], double, double, double) nogil
  5 +cdef double tricubicInterpolate (image_t[:, :, :], double, double, double) nogil
  6 +cdef double lanczos3 (image_t[:, :, :], double, double, double) nogil
  7 +
  8 +cdef double nearest_neighbour_interp(image_t[:, :, :], double, double, double) nogil
invesalius_cy/interpolation.pyx 0 → 100644
@@ -0,0 +1,392 @@ @@ -0,0 +1,392 @@
  1 +# from interpolation cimport interpolate
  2 +
  3 +import numpy as np
  4 +cimport numpy as np
  5 +cimport cython
  6 +
  7 +from libc.math cimport floor, ceil, sqrt, fabs, sin, M_PI
  8 +from cython.parallel import prange
  9 +
  10 +DEF LANCZOS_A = 4
  11 +DEF SIZE_LANCZOS_TMP = LANCZOS_A * 2 - 1
  12 +
  13 +cdef double[64][64] temp = [
  14 + [ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  15 + [ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  16 + [-3, 3, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  17 + [ 2, -2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  18 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  19 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  20 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  21 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  22 + [-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  23 + [ 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  24 + [ 9, -9,-9, 9, 0, 0, 0, 0, 6, 3,-6,-3, 0, 0, 0, 0, 6,-6, 3,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  25 + [-6, 6, 6,-6, 0, 0, 0, 0,-3,-3, 3, 3, 0, 0, 0, 0,-4, 4,-2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-2,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  26 + [ 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  27 + [ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  28 + [-6, 6, 6,-6, 0, 0, 0, 0,-4,-2, 4, 2, 0, 0, 0, 0,-3, 3,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  29 + [ 4, -4,-4, 4, 0, 0, 0, 0, 2, 2,-2,-2, 0, 0, 0, 0, 2,-2, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  30 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  31 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  32 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  33 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  34 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  35 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
  36 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0],
  37 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0],
  38 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  39 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0, 0, 0, 0, 0],
  40 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,-9,-9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3,-6,-3, 0, 0, 0, 0, 6,-6, 3,-3, 0, 0, 0, 0, 4, 2, 2, 1, 0, 0, 0, 0],
  41 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3,-3, 3, 3, 0, 0, 0, 0,-4, 4,-2, 2, 0, 0, 0, 0,-2,-2,-1,-1, 0, 0, 0, 0],
  42 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  43 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0],
  44 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4,-2, 4, 2, 0, 0, 0, 0,-3, 3,-3, 3, 0, 0, 0, 0,-2,-1,-2,-1, 0, 0, 0, 0],
  45 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,-4,-4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2,-2,-2, 0, 0, 0, 0, 2,-2, 2,-2, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0],
  46 + [-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  47 + [ 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  48 + [ 9, -9, 0, 0,-9, 9, 0, 0, 6, 3, 0, 0,-6,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,-6, 0, 0, 3,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  49 + [-6, 6, 0, 0, 6,-6, 0, 0,-3,-3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 4, 0, 0,-2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-2, 0, 0,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  50 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  51 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0, 0, 0,-1, 0, 0, 0],
  52 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,-9, 0, 0,-9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, 0, 0,-6,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6,-6, 0, 0, 3,-3, 0, 0, 4, 2, 0, 0, 2, 1, 0, 0],
  53 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 0, 0, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3,-3, 0, 0, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 4, 0, 0,-2, 2, 0, 0,-2,-2, 0, 0,-1,-1, 0, 0],
  54 + [ 9, 0,-9, 0,-9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0,-6, 0,-3, 0, 6, 0,-6, 0, 3, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  55 + [ 0, 0, 0, 0, 0, 0, 0, 0, 9, 0,-9, 0,-9, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 3, 0,-6, 0,-3, 0, 6, 0,-6, 0, 3, 0,-3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 2, 0, 2, 0, 1, 0],
  56 + [-27, 27,27,-27,27,-27,-27,27,-18,-9,18, 9,18, 9,-18,-9,-18,18,-9, 9,18,-18, 9,-9,-18,18,18,-18,-9, 9, 9,-9,-12,-6,-6,-3,12, 6, 6, 3,-12,-6,12, 6,-6,-3, 6, 3,-12,12,-6, 6,-6, 6,-3, 3,-8,-4,-4,-2,-4,-2,-2,-1],
  57 + [18, -18,-18,18,-18,18,18,-18, 9, 9,-9,-9,-9,-9, 9, 9,12,-12, 6,-6,-12,12,-6, 6,12,-12,-12,12, 6,-6,-6, 6, 6, 6, 3, 3,-6,-6,-3,-3, 6, 6,-6,-6, 3, 3,-3,-3, 8,-8, 4,-4, 4,-4, 2,-2, 4, 4, 2, 2, 2, 2, 1, 1],
  58 + [-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0,-3, 0, 3, 0, 3, 0,-4, 0, 4, 0,-2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-2, 0,-1, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  59 + [ 0, 0, 0, 0, 0, 0, 0, 0,-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 0,-3, 0, 3, 0, 3, 0,-4, 0, 4, 0,-2, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-2, 0,-1, 0,-1, 0],
  60 + [18, -18,-18,18,-18,18,18,-18,12, 6,-12,-6,-12,-6,12, 6, 9,-9, 9,-9,-9, 9,-9, 9,12,-12,-12,12, 6,-6,-6, 6, 6, 3, 6, 3,-6,-3,-6,-3, 8, 4,-8,-4, 4, 2,-4,-2, 6,-6, 6,-6, 3,-3, 3,-3, 4, 2, 4, 2, 2, 1, 2, 1],
  61 + [-12, 12,12,-12,12,-12,-12,12,-6,-6, 6, 6, 6, 6,-6,-6,-6, 6,-6, 6, 6,-6, 6,-6,-8, 8, 8,-8,-4, 4, 4,-4,-3,-3,-3,-3, 3, 3, 3, 3,-4,-4, 4, 4,-2,-2, 2, 2,-4, 4,-4, 4,-2, 2,-2, 2,-2,-2,-2,-2,-1,-1,-1,-1],
  62 + [ 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  63 + [ 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  64 + [-6, 6, 0, 0, 6,-6, 0, 0,-4,-2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0,-2,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  65 + [ 4, -4, 0, 0,-4, 4, 0, 0, 2, 2, 0, 0,-2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  66 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  67 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0],
  68 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-6, 6, 0, 0, 6,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4,-2, 0, 0, 4, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-3, 3, 0, 0,-3, 3, 0, 0,-2,-1, 0, 0,-2,-1, 0, 0],
  69 + [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4,-4, 0, 0,-4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0,-2,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,-2, 0, 0, 2,-2, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0],
  70 + [-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0,-2, 0, 4, 0, 2, 0,-3, 0, 3, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0,-2, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  71 + [ 0, 0, 0, 0, 0, 0, 0, 0,-6, 0, 6, 0, 6, 0,-6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-4, 0,-2, 0, 4, 0, 2, 0,-3, 0, 3, 0,-3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0,-2, 0,-1, 0,-2, 0,-1, 0],
  72 + [18, -18,-18,18,-18,18,18,-18,12, 6,-12,-6,-12,-6,12, 6,12,-12, 6,-6,-12,12,-6, 6, 9,-9,-9, 9, 9,-9,-9, 9, 8, 4, 4, 2,-8,-4,-4,-2, 6, 3,-6,-3, 6, 3,-6,-3, 6,-6, 3,-3, 6,-6, 3,-3, 4, 2, 2, 1, 4, 2, 2, 1],
  73 + [-12, 12,12,-12,12,-12,-12,12,-6,-6, 6, 6, 6, 6,-6,-6,-8, 8,-4, 4, 8,-8, 4,-4,-6, 6, 6,-6,-6, 6, 6,-6,-4,-4,-2,-2, 4, 4, 2, 2,-3,-3, 3, 3,-3,-3, 3, 3,-4, 4,-2, 2,-4, 4,-2, 2,-2,-2,-1,-1,-2,-2,-1,-1],
  74 + [ 4, 0,-4, 0,-4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0,-2, 0,-2, 0, 2, 0,-2, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
  75 + [ 0, 0, 0, 0, 0, 0, 0, 0, 4, 0,-4, 0,-4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0,-2, 0,-2, 0, 2, 0,-2, 0, 2, 0,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0],
  76 + [-12, 12,12,-12,12,-12,-12,12,-8,-4, 8, 4, 8, 4,-8,-4,-6, 6,-6, 6, 6,-6, 6,-6,-6, 6, 6,-6,-6, 6, 6,-6,-4,-2,-4,-2, 4, 2, 4, 2,-4,-2, 4, 2,-4,-2, 4, 2,-3, 3,-3, 3,-3, 3,-3, 3,-2,-1,-2,-1,-2,-1,-2,-1],
  77 + [ 8, -8,-8, 8,-8, 8, 8,-8, 4, 4,-4,-4,-4,-4, 4, 4, 4,-4, 4,-4,-4, 4,-4, 4, 4,-4,-4, 4, 4,-4,-4, 4, 2, 2, 2, 2,-2,-2,-2,-2, 2, 2,-2,-2, 2, 2,-2,-2, 2,-2, 2,-2, 2,-2, 2,-2, 1, 1, 1, 1, 1, 1, 1, 1]
  78 +]
  79 +
  80 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  81 +@cython.cdivision(True)
  82 +@cython.wraparound(False)
  83 +cdef double nearest_neighbour_interp(image_t[:, :, :] V, double x, double y, double z) nogil:
  84 + return V[<int>(z), <int>(y), <int>(x)]
  85 +
  86 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  87 +@cython.cdivision(True)
  88 +@cython.wraparound(False)
  89 +cdef double interpolate(image_t[:, :, :] V, double x, double y, double z) nogil:
  90 + cdef double xd, yd, zd
  91 + cdef double c00, c10, c01, c11
  92 + cdef double c0, c1
  93 + cdef double c
  94 +
  95 + cdef int x0 = <int>floor(x)
  96 + cdef int x1 = x0 + 1
  97 +
  98 + cdef int y0 = <int>floor(y)
  99 + cdef int y1 = y0 + 1
  100 +
  101 + cdef int z0 = <int>floor(z)
  102 + cdef int z1 = z0 + 1
  103 +
  104 + if x0 == x1:
  105 + xd = 1.0
  106 + else:
  107 + xd = (x - x0) / (x1 - x0)
  108 +
  109 + if y0 == y1:
  110 + yd = 1.0
  111 + else:
  112 + yd = (y - y0) / (y1 - y0)
  113 +
  114 + if z0 == z1:
  115 + zd = 1.0
  116 + else:
  117 + zd = (z - z0) / (z1 - z0)
  118 +
  119 + c00 = _G(V, x0, y0, z0)*(1 - xd) + _G(V, x1, y0, z0)*xd
  120 + c10 = _G(V, x0, y1, z0)*(1 - xd) + _G(V, x1, y1, z0)*xd
  121 + c01 = _G(V, x0, y0, z1)*(1 - xd) + _G(V, x1, y0, z1)*xd
  122 + c11 = _G(V, x0, y1, z1)*(1 - xd) + _G(V, x1, y1, z1)*xd
  123 +
  124 + c0 = c00*(1 - yd) + c10*yd
  125 + c1 = c01*(1 - yd) + c11*yd
  126 +
  127 + c = c0*(1 - zd) + c1*zd
  128 +
  129 + return c
  130 +
  131 +
  132 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  133 +@cython.cdivision(True)
  134 +@cython.wraparound(False)
  135 +cdef inline double lanczos3_L(double x, int a) nogil:
  136 + if x == 0:
  137 + return 1.0
  138 + elif -a <= x < a:
  139 + return (a * sin(M_PI * x) * sin(M_PI * (x / a)))/(M_PI**2 * x**2)
  140 + else:
  141 + return 0.0
  142 +
  143 +
  144 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  145 +@cython.cdivision(True)
  146 +@cython.wraparound(False)
  147 +cdef double lanczos3(image_t[:, :, :] V, double x, double y, double z) nogil:
  148 + cdef int a = LANCZOS_A
  149 +
  150 + cdef int xd = <int>floor(x)
  151 + cdef int yd = <int>floor(y)
  152 + cdef int zd = <int>floor(z)
  153 +
  154 + cdef int xi = xd - a + 1
  155 + cdef int xf = xd + a
  156 +
  157 + cdef int yi = yd - a + 1
  158 + cdef int yf = yd + a
  159 +
  160 + cdef int zi = zd - a + 1
  161 + cdef int zf = zd + a
  162 +
  163 + cdef double lx = 0.0
  164 + cdef double ly = 0.0
  165 + cdef double lz = 0.0
  166 +
  167 + cdef double[SIZE_LANCZOS_TMP][SIZE_LANCZOS_TMP] temp_x
  168 + cdef double[SIZE_LANCZOS_TMP] temp_y
  169 +
  170 + cdef int i, j, k
  171 + cdef int m, n, o
  172 +
  173 + m = 0
  174 + for k in xrange(zi, zf):
  175 + n = 0
  176 + for j in xrange(yi, yf):
  177 + lx = 0
  178 + for i in xrange(xi, xf):
  179 + lx += _G(V, i, j, k) * lanczos3_L(x - i, a)
  180 + temp_x[m][n] = lx
  181 + n += 1
  182 + m += 1
  183 +
  184 + m = 0
  185 + for k in xrange(zi, zf):
  186 + n = 0
  187 + ly = 0
  188 + for j in xrange(yi, yf):
  189 + ly += temp_x[m][n] * lanczos3_L(y - j, a)
  190 + n += 1
  191 + temp_y[m] = ly
  192 + m += 1
  193 +
  194 + m = 0
  195 + for k in xrange(zi, zf):
  196 + lz += temp_y[m] * lanczos3_L(z - k, a)
  197 + m += 1
  198 +
  199 + return lz
  200 +
  201 +
  202 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  203 +@cython.cdivision(True)
  204 +@cython.wraparound(False)
  205 +cdef image_t _G(image_t[:, :, :] V, int x, int y, int z) nogil:
  206 + cdef int dz, dy, dx
  207 + dz = V.shape[0] - 1
  208 + dy = V.shape[1] - 1
  209 + dx = V.shape[2] - 1
  210 +
  211 + if x < 0:
  212 + x = dx + x + 1
  213 + elif x > dx:
  214 + x = x - dx - 1
  215 +
  216 + if y < 0:
  217 + y = dy + y + 1
  218 + elif y > dy:
  219 + y = y - dy - 1
  220 +
  221 + if z < 0:
  222 + z = dz + z + 1
  223 + elif z > dz:
  224 + z = z - dz - 1
  225 +
  226 + return V[z, y, x]
  227 +
  228 +
  229 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  230 +@cython.cdivision(True)
  231 +@cython.wraparound(False)
  232 +cdef void calc_coef_tricub(image_t[:, :, :] V, double x, double y, double z, double [64] coef) nogil:
  233 + cdef int xi = <int>floor(x)
  234 + cdef int yi = <int>floor(y)
  235 + cdef int zi = <int>floor(z)
  236 +
  237 + cdef double[64] _x
  238 +
  239 + cdef int i, j
  240 +
  241 + _x[0] = _G(V, xi, yi, zi)
  242 + _x[1] = _G(V, xi + 1, yi, zi)
  243 + _x[2] = _G(V, xi, yi + 1, zi)
  244 + _x[3] = _G(V, xi + 1, yi + 1, zi)
  245 + _x[4] = _G(V, xi, yi, zi + 1)
  246 + _x[5] = _G(V, xi + 1, yi, zi + 1)
  247 + _x[6] = _G(V, xi, yi + 1, zi + 1)
  248 + _x[7] = _G(V, xi + 1, yi + 1, zi + 1)
  249 +
  250 + _x[8] = 0.5*(_G(V, xi+1,yi,zi) - _G(V, xi-1, yi, zi))
  251 + _x[9] = 0.5*(_G(V, xi+2,yi,zi) - _G(V, xi, yi, zi))
  252 + _x[10] = 0.5*(_G(V, xi+1, yi+1,zi) - _G(V, xi-1, yi+1, zi))
  253 + _x[11] = 0.5*(_G(V, xi+2, yi+1,zi) - _G(V, xi, yi+1, zi))
  254 + _x[12] = 0.5*(_G(V, xi+1, yi,zi+1) - _G(V, xi-1, yi, zi+1))
  255 + _x[13] = 0.5*(_G(V, xi+2, yi,zi+1) - _G(V, xi, yi, zi+1))
  256 + _x[14] = 0.5*(_G(V, xi+1, yi+1,zi+1) - _G(V, xi-1, yi+1, zi+1))
  257 + _x[15] = 0.5*(_G(V, xi+2, yi+1,zi+1) - _G(V, xi, yi+1, zi+1))
  258 + _x[16] = 0.5*(_G(V, xi, yi+1,zi) - _G(V, xi, yi-1, zi))
  259 + _x[17] = 0.5*(_G(V, xi+1, yi+1,zi) - _G(V, xi+1, yi-1, zi))
  260 + _x[18] = 0.5*(_G(V, xi, yi+2,zi) - _G(V, xi, yi, zi))
  261 + _x[19] = 0.5*(_G(V, xi+1, yi+2,zi) - _G(V, xi+1, yi, zi))
  262 + _x[20] = 0.5*(_G(V, xi, yi+1,zi+1) - _G(V, xi, yi-1, zi+1))
  263 + _x[21] = 0.5*(_G(V, xi+1, yi+1,zi+1) - _G(V, xi+1, yi-1, zi+1))
  264 + _x[22] = 0.5*(_G(V, xi, yi+2,zi+1) - _G(V, xi, yi, zi+1))
  265 + _x[23] = 0.5*(_G(V, xi+1, yi+2,zi+1) - _G(V, xi+1, yi, zi+1))
  266 + _x[24] = 0.5*(_G(V, xi, yi,zi+1) - _G(V, xi, yi, zi-1))
  267 + _x[25] = 0.5*(_G(V, xi+1, yi,zi+1) - _G(V, xi+1, yi, zi-1))
  268 + _x[26] = 0.5*(_G(V, xi, yi+1,zi+1) - _G(V, xi, yi+1, zi-1))
  269 + _x[27] = 0.5*(_G(V, xi+1, yi+1,zi+1) - _G(V, xi+1, yi+1, zi-1))
  270 + _x[28] = 0.5*(_G(V, xi, yi,zi+2) - _G(V, xi, yi, zi))
  271 + _x[29] = 0.5*(_G(V, xi+1, yi,zi+2) - _G(V, xi+1, yi, zi))
  272 + _x[30] = 0.5*(_G(V, xi, yi+1,zi+2) - _G(V, xi, yi+1, zi))
  273 + _x[31] = 0.5*(_G(V, xi+1, yi+1,zi+2) - _G(V, xi+1, yi+1, zi))
  274 +
  275 + _x [32] = 0.25*(_G(V, xi+1, yi+1, zi) - _G(V, xi-1, yi+1, zi) - _G(V, xi+1, yi-1, zi) + _G(V, xi-1, yi-1, zi))
  276 + _x [33] = 0.25*(_G(V, xi+2, yi+1, zi) - _G(V, xi, yi+1, zi) - _G(V, xi+2, yi-1, zi) + _G(V, xi, yi-1, zi))
  277 + _x [34] = 0.25*(_G(V, xi+1, yi+2, zi) - _G(V, xi-1, yi+2, zi) - _G(V, xi+1, yi, zi) + _G(V, xi-1, yi, zi))
  278 + _x [35] = 0.25*(_G(V, xi+2, yi+2, zi) - _G(V, xi, yi+2, zi) - _G(V, xi+2, yi, zi) + _G(V, xi, yi, zi))
  279 + _x [36] = 0.25*(_G(V, xi+1, yi+1, zi+1) - _G(V, xi-1, yi+1, zi+1) - _G(V, xi+1, yi-1, zi+1) + _G(V, xi-1, yi-1, zi+1))
  280 + _x [37] = 0.25*(_G(V, xi+2, yi+1, zi+1) - _G(V, xi, yi+1, zi+1) - _G(V, xi+2, yi-1, zi+1) + _G(V, xi, yi-1, zi+1))
  281 + _x [38] = 0.25*(_G(V, xi+1, yi+2, zi+1) - _G(V, xi-1, yi+2, zi+1) - _G(V, xi+1, yi, zi+1) + _G(V, xi-1, yi, zi+1))
  282 + _x [39] = 0.25*(_G(V, xi+2, yi+2, zi+1) - _G(V, xi, yi+2, zi+1) - _G(V, xi+2, yi, zi+1) + _G(V, xi, yi, zi+1))
  283 + _x [40] = 0.25*(_G(V, xi+1, yi, zi+1) - _G(V, xi-1, yi, zi+1) - _G(V, xi+1, yi, zi-1) + _G(V, xi-1, yi, zi-1))
  284 + _x [41] = 0.25*(_G(V, xi+2, yi, zi+1) - _G(V, xi, yi, zi+1) - _G(V, xi+2, yi, zi-1) + _G(V, xi, yi, zi-1))
  285 + _x [42] = 0.25*(_G(V, xi+1, yi+1, zi+1) - _G(V, xi-1, yi+1, zi+1) - _G(V, xi+1, yi+1, zi-1) + _G(V, xi-1, yi+1, zi-1))
  286 + _x [43] = 0.25*(_G(V, xi+2, yi+1, zi+1) - _G(V, xi, yi+1, zi+1) - _G(V, xi+2, yi+1, zi-1) + _G(V, xi, yi+1, zi-1))
  287 + _x [44] = 0.25*(_G(V, xi+1, yi, zi+2) - _G(V, xi-1, yi, zi+2) - _G(V, xi+1, yi, zi) + _G(V, xi-1, yi, zi))
  288 + _x [45] = 0.25*(_G(V, xi+2, yi, zi+2) - _G(V, xi, yi, zi+2) - _G(V, xi+2, yi, zi) + _G(V, xi, yi, zi))
  289 + _x [46] = 0.25*(_G(V, xi+1, yi+1, zi+2) - _G(V, xi-1, yi+1, zi+2) - _G(V, xi+1, yi+1, zi) + _G(V, xi-1, yi+1, zi))
  290 + _x [47] = 0.25*(_G(V, xi+2, yi+1, zi+2) - _G(V, xi, yi+1, zi+2) - _G(V, xi+2, yi+1, zi) + _G(V, xi, yi+1, zi))
  291 + _x [48] = 0.25*(_G(V, xi, yi+1, zi+1) - _G(V, xi, yi-1, zi+1) - _G(V, xi, yi+1, zi-1) + _G(V, xi, yi-1, zi-1))
  292 + _x [49] = 0.25*(_G(V, xi+1, yi+1, zi+1) - _G(V, xi+1, yi-1, zi+1) - _G(V, xi+1, yi+1, zi-1) + _G(V, xi+1, yi-1, zi-1))
  293 + _x [50] = 0.25*(_G(V, xi, yi+2, zi+1) - _G(V, xi, yi, zi+1) - _G(V, xi, yi+2, zi-1) + _G(V, xi, yi, zi-1))
  294 + _x [51] = 0.25*(_G(V, xi+1, yi+2, zi+1) - _G(V, xi+1, yi, zi+1) - _G(V, xi+1, yi+2, zi-1) + _G(V, xi+1, yi, zi-1))
  295 + _x [52] = 0.25*(_G(V, xi, yi+1, zi+2) - _G(V, xi, yi-1, zi+2) - _G(V, xi, yi+1, zi) + _G(V, xi, yi-1, zi))
  296 + _x [53] = 0.25*(_G(V, xi+1, yi+1, zi+2) - _G(V, xi+1, yi-1, zi+2) - _G(V, xi+1, yi+1, zi) + _G(V, xi+1, yi-1, zi))
  297 + _x [54] = 0.25*(_G(V, xi, yi+2, zi+2) - _G(V, xi, yi, zi+2) - _G(V, xi, yi+2, zi) + _G(V, xi, yi, zi))
  298 + _x [55] = 0.25*(_G(V, xi+1, yi+2, zi+2) - _G(V, xi+1, yi, zi+2) - _G(V, xi+1, yi+2, zi) + _G(V, xi+1, yi, zi))
  299 +
  300 + _x[56] = 0.125*(_G(V, xi+1, yi+1, zi+1) - _G(V, xi-1, yi+1, zi+1) - _G(V, xi+1, yi-1, zi+1) + _G(V, xi-1, yi-1, zi+1) - _G(V, xi+1, yi+1, zi-1) + _G(V, xi-1,yi+1,zi-1)+_G(V, xi+1,yi-1,zi-1)-_G(V, xi-1,yi-1,zi-1))
  301 + _x[57] = 0.125*(_G(V, xi+2, yi+1, zi+1) - _G(V, xi, yi+1, zi+1) - _G(V, xi+2, yi-1, zi+1) + _G(V, xi, yi-1, zi+1) - _G(V, xi+2, yi+1, zi-1) + _G(V, xi,yi+1,zi-1)+_G(V, xi+2,yi-1,zi-1)-_G(V, xi,yi-1,zi-1))
  302 + _x[58] = 0.125*(_G(V, xi+1, yi+2, zi+1) - _G(V, xi-1, yi+2, zi+1) - _G(V, xi+1, yi, zi+1) + _G(V, xi-1, yi, zi+1) - _G(V, xi+1, yi+2, zi-1) + _G(V, xi-1,yi+2,zi-1)+_G(V, xi+1,yi,zi-1)-_G(V, xi-1,yi,zi-1))
  303 + _x[59] = 0.125*(_G(V, xi+2, yi+2, zi+1) - _G(V, xi, yi+2, zi+1) - _G(V, xi+2, yi, zi+1) + _G(V, xi, yi, zi+1) - _G(V, xi+2, yi+2, zi-1) + _G(V, xi,yi+2,zi-1)+_G(V, xi+2,yi,zi-1)-_G(V, xi,yi,zi-1))
  304 + _x[60] = 0.125*(_G(V, xi+1, yi+1, zi+2) - _G(V, xi-1, yi+1, zi+2) - _G(V, xi+1, yi-1, zi+2) + _G(V, xi-1, yi-1, zi+2) - _G(V, xi+1, yi+1, zi) + _G(V, xi-1,yi+1,zi)+_G(V, xi+1,yi-1,zi)-_G(V, xi-1,yi-1,zi))
  305 + _x[61] = 0.125*(_G(V, xi+2, yi+1, zi+2) - _G(V, xi, yi+1, zi+2) - _G(V, xi+2, yi-1, zi+2) + _G(V, xi, yi-1, zi+2) - _G(V, xi+2, yi+1, zi) + _G(V, xi,yi+1,zi)+_G(V, xi+2,yi-1,zi)-_G(V, xi,yi-1,zi))
  306 + _x[62] = 0.125*(_G(V, xi+1, yi+2, zi+2) - _G(V, xi-1, yi+2, zi+2) - _G(V, xi+1, yi, zi+2) + _G(V, xi-1, yi, zi+2) - _G(V, xi+1, yi+2, zi) + _G(V, xi-1,yi+2,zi)+_G(V, xi+1,yi,zi)-_G(V, xi-1,yi,zi))
  307 + _x[63] = 0.125*(_G(V, xi+2, yi+2, zi+2) - _G(V, xi, yi+2, zi+2) - _G(V, xi+2, yi, zi+2) + _G(V, xi, yi, zi+2) - _G(V, xi+2, yi+2, zi) + _G(V, xi,yi+2,zi)+_G(V, xi+2,yi,zi)-_G(V, xi,yi,zi))
  308 +
  309 + for j in prange(64):
  310 + coef[j] = 0.0
  311 + for i in xrange(64):
  312 + coef[j] += (temp[j][i] * _x[i])
  313 +
  314 +
  315 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  316 +@cython.cdivision(True)
  317 +@cython.wraparound(False)
  318 +cdef double tricub_interpolate(image_t[:, :, :] V, double x, double y, double z) nogil:
  319 + # From: Tricubic interpolation in three dimensions. Lekien and Marsden
  320 + cdef double[64] coef
  321 + cdef double result = 0.0
  322 + calc_coef_tricub(V, x, y, z, coef)
  323 +
  324 + cdef int i, j, k
  325 +
  326 + cdef int xi = <int>floor(x)
  327 + cdef int yi = <int>floor(y)
  328 + cdef int zi = <int>floor(z)
  329 +
  330 + for i in xrange(4):
  331 + for j in xrange(4):
  332 + for k in xrange(4):
  333 + result += (coef[i+4*j+16*k] * ((x-xi)**i) * ((y-yi)**j) * ((z-zi)**k))
  334 + # return V[<int>z, <int>y, <int>x]
  335 + # with gil:
  336 + # print result
  337 + return result
  338 +
  339 +
  340 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  341 +@cython.cdivision(True)
  342 +@cython.wraparound(False)
  343 +cdef double cubicInterpolate(double p[4], double x) nogil:
  344 + return p[1] + 0.5 * x*(p[2] - p[0] + x*(2.0*p[0] - 5.0*p[1] + 4.0*p[2] - p[3] + x*(3.0*(p[1] - p[2]) + p[3] - p[0])))
  345 +
  346 +
  347 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  348 +@cython.cdivision(True)
  349 +@cython.wraparound(False)
  350 +cdef double bicubicInterpolate (double p[4][4], double x, double y) nogil:
  351 + cdef double arr[4]
  352 + arr[0] = cubicInterpolate(p[0], y)
  353 + arr[1] = cubicInterpolate(p[1], y)
  354 + arr[2] = cubicInterpolate(p[2], y)
  355 + arr[3] = cubicInterpolate(p[3], y)
  356 + return cubicInterpolate(arr, x)
  357 +
  358 +
  359 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  360 +@cython.cdivision(True)
  361 +@cython.wraparound(False)
  362 +cdef double tricubicInterpolate(image_t[:, :, :] V, double x, double y, double z) nogil:
  363 + # From http://www.paulinternet.nl/?page=bicubic
  364 + cdef double p[4][4][4]
  365 +
  366 + cdef int xi = <int>floor(x)
  367 + cdef int yi = <int>floor(y)
  368 + cdef int zi = <int>floor(z)
  369 +
  370 + cdef int i, j, k
  371 +
  372 + for i in xrange(4):
  373 + for j in xrange(4):
  374 + for k in xrange(4):
  375 + p[i][j][k] = _G(V, xi + i -1, yi + j -1, zi + k - 1)
  376 +
  377 + cdef double arr[4]
  378 + arr[0] = bicubicInterpolate(p[0], y-yi, z-zi)
  379 + arr[1] = bicubicInterpolate(p[1], y-yi, z-zi)
  380 + arr[2] = bicubicInterpolate(p[2], y-yi, z-zi)
  381 + arr[3] = bicubicInterpolate(p[3], y-yi, z-zi)
  382 + return cubicInterpolate(arr, x-xi)
  383 +
  384 +
  385 +def tricub_interpolate_py(image_t[:, :, :] V, double x, double y, double z):
  386 + return tricub_interpolate(V, x, y, z)
  387 +
  388 +def tricub_interpolate2_py(image_t[:, :, :] V, double x, double y, double z):
  389 + return tricubicInterpolate(V, x, y, z)
  390 +
  391 +def trilin_interpolate_py(image_t[:, :, :] V, double x, double y, double z):
  392 + return interpolate(V, x, y, z)
invesalius_cy/mips.pyx 0 → 100644
@@ -0,0 +1,379 @@ @@ -0,0 +1,379 @@
  1 +#http://en.wikipedia.org/wiki/Local_maximum_intensity_projection
  2 +import numpy as np
  3 +cimport numpy as np
  4 +cimport cython
  5 +
  6 +from libc.math cimport floor, ceil, sqrt, fabs
  7 +from cython.parallel import prange
  8 +
  9 +DTYPE = np.uint8
  10 +ctypedef np.uint8_t DTYPE_t
  11 +
  12 +DTYPE16 = np.int16
  13 +ctypedef np.int16_t DTYPE16_t
  14 +
  15 +DTYPEF32 = np.float32
  16 +ctypedef np.float32_t DTYPEF32_t
  17 +
  18 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  19 +def lmip(np.ndarray[DTYPE16_t, ndim=3] image, int axis, DTYPE16_t tmin,
  20 + DTYPE16_t tmax, np.ndarray[DTYPE16_t, ndim=2] out):
  21 + cdef DTYPE16_t max
  22 + cdef int start
  23 + cdef int sz = image.shape[0]
  24 + cdef int sy = image.shape[1]
  25 + cdef int sx = image.shape[2]
  26 +
  27 + # AXIAL
  28 + if axis == 0:
  29 + for x in xrange(sx):
  30 + for y in xrange(sy):
  31 + max = image[0, y, x]
  32 + if max >= tmin and max <= tmax:
  33 + start = 1
  34 + else:
  35 + start = 0
  36 + for z in xrange(sz):
  37 + if image[z, y, x] > max:
  38 + max = image[z, y, x]
  39 +
  40 + elif image[z, y, x] < max and start:
  41 + break
  42 +
  43 + if image[z, y, x] >= tmin and image[z, y, x] <= tmax:
  44 + start = 1
  45 +
  46 + out[y, x] = max
  47 +
  48 + #CORONAL
  49 + elif axis == 1:
  50 + for z in xrange(sz):
  51 + for x in xrange(sx):
  52 + max = image[z, 0, x]
  53 + if max >= tmin and max <= tmax:
  54 + start = 1
  55 + else:
  56 + start = 0
  57 + for y in xrange(sy):
  58 + if image[z, y, x] > max:
  59 + max = image[z, y, x]
  60 +
  61 + elif image[z, y, x] < max and start:
  62 + break
  63 +
  64 + if image[z, y, x] >= tmin and image[z, y, x] <= tmax:
  65 + start = 1
  66 +
  67 + out[z, x] = max
  68 +
  69 + #CORONAL
  70 + elif axis == 2:
  71 + for z in xrange(sz):
  72 + for y in xrange(sy):
  73 + max = image[z, y, 0]
  74 + if max >= tmin and max <= tmax:
  75 + start = 1
  76 + else:
  77 + start = 0
  78 + for x in xrange(sx):
  79 + if image[z, y, x] > max:
  80 + max = image[z, y, x]
  81 +
  82 + elif image[z, y, x] < max and start:
  83 + break
  84 +
  85 + if image[z, y, x] >= tmin and image[z, y, x] <= tmax:
  86 + start = 1
  87 +
  88 + out[z, y] = max
  89 +
  90 +
  91 +cdef DTYPE16_t get_colour(DTYPE16_t vl, DTYPE16_t wl, DTYPE16_t ww):
  92 + cdef DTYPE16_t out_colour
  93 + cdef DTYPE16_t min_value = wl - (ww / 2)
  94 + cdef DTYPE16_t max_value = wl + (ww / 2)
  95 + if vl < min_value:
  96 + out_colour = min_value
  97 + elif vl > max_value:
  98 + out_colour = max_value
  99 + else:
  100 + out_colour = vl
  101 +
  102 + return out_colour
  103 +
  104 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  105 +@cython.cdivision(True)
  106 +cdef float get_opacity(DTYPE16_t vl, DTYPE16_t wl, DTYPE16_t ww) nogil:
  107 + cdef float out_opacity
  108 + cdef DTYPE16_t min_value = wl - (ww / 2)
  109 + cdef DTYPE16_t max_value = wl + (ww / 2)
  110 + if vl < min_value:
  111 + out_opacity = 0.0
  112 + elif vl > max_value:
  113 + out_opacity = 1.0
  114 + else:
  115 + out_opacity = 1.0/(max_value - min_value) * (vl - min_value)
  116 +
  117 + return out_opacity
  118 +
  119 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  120 +@cython.cdivision(True)
  121 +cdef float get_opacity_f32(DTYPEF32_t vl, DTYPE16_t wl, DTYPE16_t ww) nogil:
  122 + cdef float out_opacity
  123 + cdef DTYPE16_t min_value = wl - (ww / 2)
  124 + cdef DTYPE16_t max_value = wl + (ww / 2)
  125 + if vl < min_value:
  126 + out_opacity = 0.0
  127 + elif vl > max_value:
  128 + out_opacity = 1.0
  129 + else:
  130 + out_opacity = 1.0/(max_value - min_value) * (vl - min_value)
  131 +
  132 + return out_opacity
  133 +
  134 +
  135 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  136 +@cython.cdivision(True)
  137 +def mida(np.ndarray[DTYPE16_t, ndim=3] image, int axis, DTYPE16_t wl,
  138 + DTYPE16_t ww, np.ndarray[DTYPE16_t, ndim=2] out):
  139 + cdef int sz = image.shape[0]
  140 + cdef int sy = image.shape[1]
  141 + cdef int sx = image.shape[2]
  142 +
  143 + cdef DTYPE16_t min = image.min()
  144 + cdef DTYPE16_t max = image.max()
  145 + cdef DTYPE16_t vl
  146 +
  147 + cdef DTYPE16_t min_value = wl - (ww / 2)
  148 + cdef DTYPE16_t max_value = wl + (ww / 2)
  149 +
  150 + cdef float fmax=0.0
  151 + cdef float fpi
  152 + cdef float dl
  153 + cdef float bt
  154 +
  155 + cdef float alpha
  156 + cdef float alpha_p = 0.0
  157 + cdef float colour
  158 + cdef float colour_p = 0
  159 +
  160 + cdef int x, y, z
  161 +
  162 + # AXIAL
  163 + if axis == 0:
  164 + for x in prange(sx, nogil=True):
  165 + for y in xrange(sy):
  166 + fmax = 0.0
  167 + alpha_p = 0.0
  168 + colour_p = 0.0
  169 + for z in xrange(sz):
  170 + vl = image[z, y, x]
  171 + fpi = 1.0/(max - min) * (vl - min)
  172 + if fpi > fmax:
  173 + dl = fpi - fmax
  174 + fmax = fpi
  175 + else:
  176 + dl = 0.0
  177 +
  178 + bt = 1.0 - dl
  179 +
  180 + colour = fpi
  181 + alpha = get_opacity(vl, wl, ww)
  182 + colour = (bt * colour_p) + (1 - bt * alpha_p) * colour * alpha
  183 + alpha = (bt * alpha_p) + (1 - bt * alpha_p) * alpha
  184 +
  185 + colour_p = colour
  186 + alpha_p = alpha
  187 +
  188 + if alpha >= 1.0:
  189 + break
  190 +
  191 +
  192 + #out[y, x] = <DTYPE16_t>((max_value - min_value) * colour + min_value)
  193 + out[y, x] = <DTYPE16_t>((max - min) * colour + min)
  194 +
  195 +
  196 + #CORONAL
  197 + elif axis == 1:
  198 + for z in prange(sz, nogil=True):
  199 + for x in xrange(sx):
  200 + fmax = 0.0
  201 + alpha_p = 0.0
  202 + colour_p = 0.0
  203 + for y in xrange(sy):
  204 + vl = image[z, y, x]
  205 + fpi = 1.0/(max - min) * (vl - min)
  206 + if fpi > fmax:
  207 + dl = fpi - fmax
  208 + fmax = fpi
  209 + else:
  210 + dl = 0.0
  211 +
  212 + bt = 1.0 - dl
  213 +
  214 + colour = fpi
  215 + alpha = get_opacity(vl, wl, ww)
  216 + colour = (bt * colour_p) + (1 - bt * alpha_p) * colour * alpha
  217 + alpha = (bt * alpha_p) + (1 - bt * alpha_p) * alpha
  218 +
  219 + colour_p = colour
  220 + alpha_p = alpha
  221 +
  222 + if alpha >= 1.0:
  223 + break
  224 +
  225 + out[z, x] = <DTYPE16_t>((max - min) * colour + min)
  226 +
  227 + #AXIAL
  228 + elif axis == 2:
  229 + for z in prange(sz, nogil=True):
  230 + for y in xrange(sy):
  231 + fmax = 0.0
  232 + alpha_p = 0.0
  233 + colour_p = 0.0
  234 + for x in xrange(sx):
  235 + vl = image[z, y, x]
  236 + fpi = 1.0/(max - min) * (vl - min)
  237 + if fpi > fmax:
  238 + dl = fpi - fmax
  239 + fmax = fpi
  240 + else:
  241 + dl = 0.0
  242 +
  243 + bt = 1.0 - dl
  244 +
  245 + colour = fpi
  246 + alpha = get_opacity(vl, wl, ww)
  247 + colour = (bt * colour_p) + (1 - bt * alpha_p) * colour * alpha
  248 + alpha = (bt * alpha_p) + (1 - bt * alpha_p) * alpha
  249 +
  250 + colour_p = colour
  251 + alpha_p = alpha
  252 +
  253 + if alpha >= 1.0:
  254 + break
  255 +
  256 + out[z, y] = <DTYPE16_t>((max - min) * colour + min)
  257 +
  258 +
  259 +
  260 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  261 +@cython.cdivision(True)
  262 +cdef inline void finite_difference(DTYPE16_t[:, :, :] image,
  263 + int x, int y, int z, float h, float *g) nogil:
  264 + cdef int px, py, pz, fx, fy, fz
  265 +
  266 + cdef int sz = image.shape[0]
  267 + cdef int sy = image.shape[1]
  268 + cdef int sx = image.shape[2]
  269 +
  270 + cdef float gx, gy, gz
  271 +
  272 + if x == 0:
  273 + px = 0
  274 + fx = 1
  275 + elif x == sx - 1:
  276 + px = x - 1
  277 + fx = x
  278 + else:
  279 + px = x - 1
  280 + fx = x + 1
  281 +
  282 + if y == 0:
  283 + py = 0
  284 + fy = 1
  285 + elif y == sy - 1:
  286 + py = y - 1
  287 + fy = y
  288 + else:
  289 + py = y - 1
  290 + fy = y + 1
  291 +
  292 + if z == 0:
  293 + pz = 0
  294 + fz = 1
  295 + elif z == sz - 1:
  296 + pz = z - 1
  297 + fz = z
  298 + else:
  299 + pz = z - 1
  300 + fz = z + 1
  301 +
  302 + gx = (image[z, y, fx] - image[z, y, px]) / (2*h)
  303 + gy = (image[z, fy, x] - image[z, py, x]) / (2*h)
  304 + gz = (image[fz, y, x] - image[pz, y, x]) / (2*h)
  305 +
  306 + g[0] = gx
  307 + g[1] = gy
  308 + g[2] = gz
  309 +
  310 +
  311 +
  312 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  313 +@cython.cdivision(True)
  314 +cdef inline float calc_fcm_itensity(DTYPE16_t[:, :, :] image,
  315 + int x, int y, int z, float n, float* dir) nogil:
  316 + cdef float g[3]
  317 + finite_difference(image, x, y, z, 1.0, g)
  318 + cdef float gm = sqrt(g[0]*g[0] + g[1]*g[1] + g[2]*g[2])
  319 + cdef float d = g[0]*dir[0] + g[1]*dir[1] + g[2]*dir[2]
  320 + cdef float sf = (1.0 - fabs(d/gm))**n
  321 + #alpha = get_opacity_f32(gm, wl, ww)
  322 + cdef float vl = gm * sf
  323 + return vl
  324 +
  325 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  326 +@cython.cdivision(True)
  327 +def fast_countour_mip(np.ndarray[DTYPE16_t, ndim=3] image,
  328 + float n,
  329 + int axis,
  330 + DTYPE16_t wl, DTYPE16_t ww,
  331 + int tmip,
  332 + np.ndarray[DTYPE16_t, ndim=2] out):
  333 + cdef int sz = image.shape[0]
  334 + cdef int sy = image.shape[1]
  335 + cdef int sx = image.shape[2]
  336 + cdef float gm
  337 + cdef float alpha
  338 + cdef float sf
  339 + cdef float d
  340 +
  341 + cdef float* g
  342 + cdef float* dir = [ 0, 0, 0 ]
  343 +
  344 + cdef DTYPE16_t[:, :, :] vimage = image
  345 + cdef np.ndarray[DTYPE16_t, ndim=3] tmp = np.empty_like(image)
  346 +
  347 + cdef DTYPE16_t min = image.min()
  348 + cdef DTYPE16_t max = image.max()
  349 + cdef float fmin = <float>min
  350 + cdef float fmax = <float>max
  351 + cdef float vl
  352 + cdef DTYPE16_t V
  353 +
  354 + cdef int x, y, z
  355 +
  356 + if axis == 0:
  357 + dir[2] = 1.0
  358 + elif axis == 1:
  359 + dir[1] = 1.0
  360 + elif axis == 2:
  361 + dir[0] = 1.0
  362 +
  363 + for z in prange(sz, nogil=True):
  364 + for y in range(sy):
  365 + for x in range(sx):
  366 + vl = calc_fcm_itensity(vimage, x, y, z, n, dir)
  367 + tmp[z, y, x] = <DTYPE16_t>vl
  368 +
  369 + cdef DTYPE16_t tmin = tmp.min()
  370 + cdef DTYPE16_t tmax = tmp.max()
  371 +
  372 + #tmp = ((max - min)/<float>(tmax - tmin)) * (tmp - tmin) + min
  373 +
  374 + if tmip == 0:
  375 + out[:] = tmp.max(axis)
  376 + elif tmip == 1:
  377 + lmip(tmp, axis, 700, 3033, out)
  378 + elif tmip == 2:
  379 + mida(tmp, axis, wl, ww, out)
invesalius_cy/transforms.pyx 0 → 100644
@@ -0,0 +1,174 @@ @@ -0,0 +1,174 @@
  1 +import numpy as np
  2 +cimport numpy as np
  3 +cimport cython
  4 +
  5 +from .cy_my_types cimport image_t
  6 +from .interpolation cimport interpolate, tricub_interpolate, tricubicInterpolate, lanczos3, nearest_neighbour_interp
  7 +
  8 +from libc.math cimport floor, ceil, sqrt, fabs, round
  9 +from cython.parallel import prange
  10 +
  11 +ctypedef double (*interp_function)(image_t[:, :, :], double, double, double) nogil
  12 +
  13 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  14 +@cython.cdivision(True)
  15 +@cython.wraparound(False)
  16 +cdef void mul_mat4_vec4(double[:, :] M,
  17 + double* coord,
  18 + double* out) nogil:
  19 +
  20 + out[0] = coord[0] * M[0, 0] + coord[1] * M[0, 1] + coord[2] * M[0, 2] + coord[3] * M[0, 3]
  21 + out[1] = coord[0] * M[1, 0] + coord[1] * M[1, 1] + coord[2] * M[1, 2] + coord[3] * M[1, 3]
  22 + out[2] = coord[0] * M[2, 0] + coord[1] * M[2, 1] + coord[2] * M[2, 2] + coord[3] * M[2, 3]
  23 + out[3] = coord[0] * M[3, 0] + coord[1] * M[3, 1] + coord[2] * M[3, 2] + coord[3] * M[3, 3]
  24 +
  25 +
  26 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  27 +@cython.cdivision(True)
  28 +@cython.wraparound(False)
  29 +cdef image_t coord_transform(image_t[:, :, :] volume, double[:, :] M, int x, int y, int z, double sx, double sy, double sz, interp_function f_interp, image_t cval) nogil:
  30 +
  31 + cdef double coord[4]
  32 + coord[0] = z*sz
  33 + coord[1] = y*sy
  34 + coord[2] = x*sx
  35 + coord[3] = 1.0
  36 +
  37 + cdef double _ncoord[4]
  38 + _ncoord[3] = 1
  39 + # _ncoord[:] = [0.0, 0.0, 0.0, 1.0]
  40 +
  41 + cdef unsigned int dz, dy, dx
  42 + dz = volume.shape[0]
  43 + dy = volume.shape[1]
  44 + dx = volume.shape[2]
  45 +
  46 +
  47 + mul_mat4_vec4(M, coord, _ncoord)
  48 +
  49 + cdef double nz, ny, nx
  50 + nz = (_ncoord[0]/_ncoord[3])/sz
  51 + ny = (_ncoord[1]/_ncoord[3])/sy
  52 + nx = (_ncoord[2]/_ncoord[3])/sx
  53 +
  54 + cdef double v
  55 +
  56 + if 0 <= nz <= (dz-1) and 0 <= ny <= (dy-1) and 0 <= nx <= (dx-1):
  57 + return <image_t>f_interp(volume, nx, ny, nz)
  58 + # if minterpol == 0:
  59 + # return <image_t>nearest_neighbour_interp(volume, nx, ny, nz)
  60 + # elif minterpol == 1:
  61 + # return <image_t>interpolate(volume, nx, ny, nz)
  62 + # elif minterpol == 2:
  63 + # v = tricubicInterpolate(volume, nx, ny, nz)
  64 + # if (v < cval):
  65 + # v = cval
  66 + # return <image_t>v
  67 + # else:
  68 + # v = lanczos3(volume, nx, ny, nz)
  69 + # if (v < cval):
  70 + # v = cval
  71 + # return <image_t>v
  72 + else:
  73 + return cval
  74 +
  75 +
  76 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  77 +@cython.cdivision(True)
  78 +@cython.wraparound(False)
  79 +def apply_view_matrix_transform(image_t[:, :, :] volume,
  80 + spacing,
  81 + double[:, :] M,
  82 + unsigned int n, str orientation,
  83 + int minterpol,
  84 + image_t cval,
  85 + image_t[:, :, :] out):
  86 +
  87 + cdef int dz, dy, dx
  88 + cdef int z, y, x
  89 + dz = volume.shape[0]
  90 + dy = volume.shape[1]
  91 + dx = volume.shape[2]
  92 +
  93 + cdef unsigned int odz, ody, odx
  94 + odz = out.shape[0]
  95 + ody = out.shape[1]
  96 + odx = out.shape[2]
  97 +
  98 + cdef unsigned int count = 0
  99 +
  100 + cdef double sx, sy, sz
  101 + sx = spacing[0]
  102 + sy = spacing[1]
  103 + sz = spacing[2]
  104 +
  105 + cdef interp_function f_interp
  106 +
  107 + if minterpol == 0:
  108 + f_interp = nearest_neighbour_interp
  109 + elif minterpol == 1:
  110 + f_interp = interpolate
  111 + elif minterpol == 2:
  112 + f_interp = tricubicInterpolate
  113 + else:
  114 + f_interp = lanczos3
  115 +
  116 + if orientation == 'AXIAL':
  117 + for z in xrange(n, n+odz):
  118 + for y in prange(dy, nogil=True):
  119 + for x in xrange(dx):
  120 + out[count, y, x] = coord_transform(volume, M, x, y, z, sx, sy, sz, f_interp, cval)
  121 + count += 1
  122 +
  123 + elif orientation == 'CORONAL':
  124 + for y in xrange(n, n+ody):
  125 + for z in prange(dz, nogil=True):
  126 + for x in xrange(dx):
  127 + out[z, count, x] = coord_transform(volume, M, x, y, z, sx, sy, sz, f_interp, cval)
  128 + count += 1
  129 +
  130 + elif orientation == 'SAGITAL':
  131 + for x in xrange(n, n+odx):
  132 + for z in prange(dz, nogil=True):
  133 + for y in xrange(dy):
  134 + out[z, y, count] = coord_transform(volume, M, x, y, z, sx, sy, sz, f_interp, cval)
  135 + count += 1
  136 +
  137 +
  138 +@cython.boundscheck(False) # turn of bounds-checking for entire function
  139 +@cython.cdivision(True)
  140 +@cython.wraparound(False)
  141 +def convolve_non_zero(image_t[:, :, :] volume,
  142 + image_t[:, :, :] kernel,
  143 + image_t cval):
  144 + cdef Py_ssize_t x, y, z, sx, sy, sz, kx, ky, kz, skx, sky, skz, i, j, k
  145 + cdef image_t v
  146 +
  147 + cdef image_t[:, :, :] out = np.zeros_like(volume)
  148 +
  149 + sz = volume.shape[0]
  150 + sy = volume.shape[1]
  151 + sx = volume.shape[2]
  152 +
  153 + skz = kernel.shape[0]
  154 + sky = kernel.shape[1]
  155 + skx = kernel.shape[2]
  156 +
  157 + for z in prange(sz, nogil=True):
  158 + for y in xrange(sy):
  159 + for x in xrange(sx):
  160 + if volume[z, y, x] != 0:
  161 + for k in xrange(skz):
  162 + kz = z - skz // 2 + k
  163 + for j in xrange(sky):
  164 + ky = y - sky // 2 + j
  165 + for i in xrange(skx):
  166 + kx = x - skx // 2 + i
  167 +
  168 + if 0 <= kz < sz and 0 <= ky < sy and 0 <= kx < sx:
  169 + v = volume[kz, ky, kx]
  170 + else:
  171 + v = cval
  172 +
  173 + out[z, y, x] += (v * kernel[k, j, i])
  174 + return np.asarray(out)
@@ -40,25 +40,25 @@ setup( @@ -40,25 +40,25 @@ setup(
40 ext_modules=cythonize( 40 ext_modules=cythonize(
41 [ 41 [
42 Extension( 42 Extension(
43 - "invesalius.data.mips",  
44 - ["invesalius/data/mips.pyx"], 43 + "invesalius_cy.mips",
  44 + ["invesalius_cy/mips.pyx"],
45 ), 45 ),
46 Extension( 46 Extension(
47 - "invesalius.data.interpolation",  
48 - ["invesalius/data/interpolation.pyx"], 47 + "invesalius_cy.interpolation",
  48 + ["invesalius_cy/interpolation.pyx"],
49 ), 49 ),
50 Extension( 50 Extension(
51 - "invesalius.data.transforms",  
52 - ["invesalius/data/transforms.pyx"], 51 + "invesalius_cy.transforms",
  52 + ["invesalius_cy/transforms.pyx"],
53 ), 53 ),
54 Extension( 54 Extension(
55 - "invesalius.data.floodfill",  
56 - ["invesalius/data/floodfill.pyx"], 55 + "invesalius_cy.floodfill",
  56 + ["invesalius_cy/floodfill.pyx"],
57 language="c++", 57 language="c++",
58 ), 58 ),
59 Extension( 59 Extension(
60 - "invesalius.data.cy_mesh",  
61 - ["invesalius/data/cy_mesh.pyx"], 60 + "invesalius_cy.cy_mesh",
  61 + ["invesalius_cy/cy_mesh.pyx"],
62 language="c++", 62 language="c++",
63 ), 63 ),
64 ] 64 ]