1
- # Copyright 2014-2017 The ODL contributors
1
+ # Copyright 2014-2018 The ODL contributors
2
2
#
3
3
# This file is part of ODL.
4
4
#
37
37
from odl .discr import DiscreteLp , DiscreteLpElement
38
38
from odl .tomo .geometry import (
39
39
Geometry , DivergentBeamGeometry , ParallelBeamGeometry ,
40
+ ParallelVecGeometry , ConeVecGeometry ,
40
41
Flat1dDetector , Flat2dDetector )
41
42
from odl .tomo .util .utility import euler_matrix
42
43
from odl .util .npy_compat import moveaxis
@@ -230,6 +231,75 @@ def astra_volume_geometry(reco_space):
230
231
return vol_geom
231
232
232
233
234
+ def vecs_odl_axes_to_astra_axes (vecs ):
235
+ """Convert geometry vectors from ODL axis convention to ASTRA.
236
+
237
+ Parameters
238
+ ----------
239
+ vecs : array-like, shape ``(N, 6)`` or ``(N, 12)``
240
+ Vectors defining the geometric configuration in each
241
+ projection. The number ``N`` of rows determines the number
242
+ of projections, and the number of columns the spatial
243
+ dimension (6 for 2D, 12 for 3D).
244
+
245
+ Returns
246
+ -------
247
+ astra_vecs : `numpy.ndarray`, same shape as ``vecs``
248
+ The converted geometry vectors.
249
+ """
250
+ vecs = np .asarray (vecs , dtype = float )
251
+
252
+ if vecs .shape [1 ] == 6 :
253
+ # 2D geometry, nothing to do since the axes are the same
254
+ return vecs
255
+ elif vecs .shape [1 ] == 12 :
256
+ # 3D geometry
257
+ # ASTRA has (z, y, x) axis convention, in contrast to (x, y, z) in ODL,
258
+ # so we need to adapt to this by changing the order.
259
+ newind = []
260
+ for i in range (4 ):
261
+ newind .extend ([2 + 3 * i , 1 + 3 * i , 0 + 3 * i ])
262
+ return vecs [:, newind ]
263
+ else :
264
+ raise ValueError ('`vecs` must have shape (N, 6) or (N, 12), got '
265
+ 'array with shape {}' .format (vecs .shape ))
266
+
267
+
268
+ def vecs_astra_axes_to_odl_axes (vecs ):
269
+ """Convert geometry vectors from ASTRA axis convention to ODL.
270
+
271
+ Parameters
272
+ ----------
273
+ vecs : array-like, shape ``(N, 6)`` or ``(N, 12)``
274
+ Vectors defining the geometric configuration in each
275
+ projection. The number ``N`` of rows determines the number
276
+ of projections, and the number of columns the spatial
277
+ dimension (6 for 2D, 12 for 3D).
278
+
279
+ Returns
280
+ -------
281
+ odl_vecs : `numpy.ndarray`, same shape as ``vecs``
282
+ The converted geometry vectors.
283
+ """
284
+ vecs = np .asarray (vecs , dtype = float )
285
+
286
+ if vecs .shape [1 ] == 6 :
287
+ # 2D geometry, nothing to do since the axes are the same
288
+ return vecs
289
+ elif vecs .shape [1 ] == 12 :
290
+ # 3D geometry
291
+ # ASTRA has (z, y, x) axis convention, in contrast to (x, y, z) in ODL,
292
+ # so we need to adapt to this by changing the order.
293
+ newind = []
294
+ for i in range (4 ):
295
+ newind .extend ([2 + 3 * i , 1 + 3 * i , 0 + 3 * i ])
296
+ newind = np .argsort (newind ).tolist ()
297
+ return vecs [:, newind ]
298
+ else :
299
+ raise ValueError ('`vecs` must have shape (N, 6) or (N, 12), got '
300
+ 'array with shape {}' .format (vecs .shape ))
301
+
302
+
233
303
def astra_conebeam_3d_geom_to_vec (geometry ):
234
304
"""Create vectors for ASTRA projection geometries from ODL geometry.
235
305
@@ -288,14 +358,7 @@ def astra_conebeam_3d_geom_to_vec(geometry):
288
358
vectors [:, 9 :12 ] = det_axes [0 ] * px_sizes [0 ]
289
359
vectors [:, 6 :9 ] = det_axes [1 ] * px_sizes [1 ]
290
360
291
- # ASTRA has (z, y, x) axis convention, in contrast to (x, y, z) in ODL,
292
- # so we need to adapt to this by changing the order.
293
- newind = []
294
- for i in range (4 ):
295
- newind += [2 + 3 * i , 1 + 3 * i , 0 + 3 * i ]
296
- vectors = vectors [:, newind ]
297
-
298
- return vectors
361
+ return vecs_odl_axes_to_astra_axes (vectors )
299
362
300
363
301
364
def astra_conebeam_2d_geom_to_vec (geometry ):
@@ -354,7 +417,7 @@ def astra_conebeam_2d_geom_to_vec(geometry):
354
417
px_size = geometry .det_partition .cell_sides [0 ]
355
418
vectors [:, 4 :6 ] = det_axis * px_size
356
419
357
- return vectors
420
+ return vecs_odl_axes_to_astra_axes ( vectors )
358
421
359
422
360
423
def astra_parallel_3d_geom_to_vec (geometry ):
@@ -416,13 +479,7 @@ def astra_parallel_3d_geom_to_vec(geometry):
416
479
vectors [:, 9 :12 ] = det_axes [0 ] * px_sizes [0 ]
417
480
vectors [:, 6 :9 ] = det_axes [1 ] * px_sizes [1 ]
418
481
419
- # ASTRA has (z, y, x) axis convention, in contrast to (x, y, z) in ODL,
420
- # so we need to adapt to this by changing the order.
421
- new_ind = []
422
- for i in range (4 ):
423
- new_ind += [2 + 3 * i , 1 + 3 * i , 0 + 3 * i ]
424
- vectors = vectors [:, new_ind ]
425
- return vectors
482
+ return vecs_odl_axes_to_astra_axes (vectors )
426
483
427
484
428
485
def astra_projection_geometry (geometry ):
@@ -472,6 +529,22 @@ def astra_projection_geometry(geometry):
472
529
vec = astra_conebeam_2d_geom_to_vec (geometry )
473
530
proj_geom = astra .create_proj_geom ('fanflat_vec' , det_count , vec )
474
531
532
+ elif isinstance (geometry , ParallelVecGeometry ) and geometry .ndim == 2 :
533
+ det_count = geometry .detector .size
534
+ vec = geometry .vectors
535
+ # TODO: flip axes?
536
+ if not astra_supports ('parallel2d_vec_geometry' ):
537
+ raise NotImplementedError (
538
+ "'parallel_vec' geometry not supported by ASTRA "
539
+ 'v{}' .format (ASTRA_VERSION ))
540
+ proj_geom = astra .create_proj_geom ('parallel_vec' , det_count , vec )
541
+
542
+ elif isinstance (geometry , ConeVecGeometry ) and geometry .ndim == 2 :
543
+ det_count = geometry .detector .size
544
+ vec = geometry .vectors
545
+ # TODO: flip axes?
546
+ proj_geom = astra .create_proj_geom ('fanflat_vec' , det_count , vec )
547
+
475
548
elif (isinstance (geometry , ParallelBeamGeometry ) and
476
549
isinstance (geometry .detector , (Flat1dDetector , Flat2dDetector )) and
477
550
geometry .ndim == 3 ):
@@ -491,6 +564,23 @@ def astra_projection_geometry(geometry):
491
564
vec = astra_conebeam_3d_geom_to_vec (geometry )
492
565
proj_geom = astra .create_proj_geom ('cone_vec' , det_row_count ,
493
566
det_col_count , vec )
567
+
568
+ elif isinstance (geometry , ParallelVecGeometry ) and geometry .ndim == 3 :
569
+ det_row_count = geometry .det_partition .shape [1 ]
570
+ det_col_count = geometry .det_partition .shape [0 ]
571
+ vec = geometry .vectors
572
+ # TODO: flip axes?
573
+ proj_geom = astra .create_proj_geom ('parallel3d_vec' , det_row_count ,
574
+ det_col_count , vec )
575
+
576
+ elif isinstance (geometry , ConeVecGeometry ) and geometry .ndim == 3 :
577
+ det_row_count = geometry .det_partition .shape [1 ]
578
+ det_col_count = geometry .det_partition .shape [0 ]
579
+ vec = geometry .vectors
580
+ # TODO: flip axes?
581
+ proj_geom = astra .create_proj_geom ('cone_vec' , det_row_count ,
582
+ det_col_count , vec )
583
+
494
584
else :
495
585
raise NotImplementedError ('unknown ASTRA geometry type {!r}'
496
586
'' .format (geometry ))
0 commit comments