52
52
53
53
from odl .discr import DiscreteLp , DiscreteLpElement
54
54
from odl .tomo .geometry import (
55
- Geometry , DivergentBeamGeometry , ParallelBeamGeometry , FlatDetector )
55
+ Geometry , DivergentBeamGeometry , ParallelBeamGeometry ,
56
+ ParallelVecGeometry , ConeVecGeometry ,
57
+ FlatDetector )
56
58
from odl .tomo .util .utility import euler_matrix
57
59
from odl .util .utility import pkg_supports
58
60
@@ -211,6 +213,75 @@ def astra_volume_geometry(discr_reco):
211
213
return vol_geom
212
214
213
215
216
+ def vecs_odl_axes_to_astra_axes (vecs ):
217
+ """Convert geometry vectors from ODL axis convention to ASTRA.
218
+
219
+ Parameters
220
+ ----------
221
+ vecs : array-like, shape ``(N, 6)`` or ``(N, 12)``
222
+ Vectors defining the geometric configuration in each
223
+ projection. The number ``N`` of rows determines the number
224
+ of projections, and the number of columns the spatial
225
+ dimension (6 for 2D, 12 for 3D).
226
+
227
+ Returns
228
+ -------
229
+ astra_vecs : `numpy.ndarray`, same shape as ``vecs``
230
+ The converted geometry vectors.
231
+ """
232
+ vecs = np .asarray (vecs , dtype = float )
233
+
234
+ if vecs .shape [1 ] == 6 :
235
+ # 2D geometry, nothing to do since the axes are the same
236
+ return vecs
237
+ elif vecs .shape [1 ] == 12 :
238
+ # 3D geometry
239
+ # ASTRA has (z, y, x) axis convention, in contrast to (x, y, z) in ODL,
240
+ # so we need to adapt to this by changing the order.
241
+ newind = []
242
+ for i in range (4 ):
243
+ newind .extend ([2 + 3 * i , 1 + 3 * i , 0 + 3 * i ])
244
+ return vecs [:, newind ]
245
+ else :
246
+ raise ValueError ('`vecs` must have shape (N, 6) or (N, 12), got '
247
+ 'array with shape {}' .format (vecs .shape ))
248
+
249
+
250
+ def vecs_astra_axes_to_odl_axes (vecs ):
251
+ """Convert geometry vectors from ASTRA axis convention to ODL.
252
+
253
+ Parameters
254
+ ----------
255
+ vecs : array-like, shape ``(N, 6)`` or ``(N, 12)``
256
+ Vectors defining the geometric configuration in each
257
+ projection. The number ``N`` of rows determines the number
258
+ of projections, and the number of columns the spatial
259
+ dimension (6 for 2D, 12 for 3D).
260
+
261
+ Returns
262
+ -------
263
+ odl_vecs : `numpy.ndarray`, same shape as ``vecs``
264
+ The converted geometry vectors.
265
+ """
266
+ vecs = np .asarray (vecs , dtype = float )
267
+
268
+ if vecs .shape [1 ] == 6 :
269
+ # 2D geometry, nothing to do since the axes are the same
270
+ return vecs
271
+ elif vecs .shape [1 ] == 12 :
272
+ # 3D geometry
273
+ # ASTRA has (z, y, x) axis convention, in contrast to (x, y, z) in ODL,
274
+ # so we need to adapt to this by changing the order.
275
+ newind = []
276
+ for i in range (4 ):
277
+ newind .extend ([2 + 3 * i , 1 + 3 * i , 0 + 3 * i ])
278
+ newind = np .argsort (newind ).tolist ()
279
+ return vecs [:, newind ]
280
+ else :
281
+ raise ValueError ('`vecs` must have shape (N, 6) or (N, 12), got '
282
+ 'array with shape {}' .format (vecs .shape ))
283
+
284
+
214
285
def astra_conebeam_3d_geom_to_vec (geometry ):
215
286
"""Create vectors for ASTRA projection geometries from ODL geometry.
216
287
@@ -261,14 +332,7 @@ def astra_conebeam_3d_geom_to_vec(geometry):
261
332
vectors [:, 6 :9 ] = det_axes [0 ] * px_sizes [0 ]
262
333
vectors [:, 9 :12 ] = det_axes [1 ] * px_sizes [1 ]
263
334
264
- # ASTRA has (z, y, x) axis convention, in contrast to (x, y, z) in ODL,
265
- # so we need to adapt to this by changing the order.
266
- newind = []
267
- for i in range (4 ):
268
- newind += [2 + 3 * i , 1 + 3 * i , 0 + 3 * i ]
269
- vectors = vectors [:, newind ]
270
-
271
- return vectors
335
+ return vecs_odl_axes_to_astra_axes (vectors )
272
336
273
337
274
338
def astra_conebeam_2d_geom_to_vec (geometry ):
@@ -325,7 +389,7 @@ def astra_conebeam_2d_geom_to_vec(geometry):
325
389
px_size = geometry .det_partition .cell_sides [0 ]
326
390
vectors [:, 4 :6 ] = det_axis * px_size
327
391
328
- return vectors
392
+ return vecs_odl_axes_to_astra_axes ( vectors )
329
393
330
394
331
395
def astra_parallel_3d_geom_to_vec (geometry ):
@@ -379,13 +443,7 @@ def astra_parallel_3d_geom_to_vec(geometry):
379
443
vectors [:, 6 :9 ] = det_axes [0 ] * px_sizes [0 ]
380
444
vectors [:, 9 :12 ] = det_axes [1 ] * px_sizes [1 ]
381
445
382
- # ASTRA has (z, y, x) axis convention, in contrast to (x, y, z) in ODL,
383
- # so we need to adapt to this by changing the order.
384
- new_ind = []
385
- for i in range (4 ):
386
- new_ind += [2 + 3 * i , 1 + 3 * i , 0 + 3 * i ]
387
- vectors = vectors [:, new_ind ]
388
- return vectors
446
+ return vecs_odl_axes_to_astra_axes (vectors )
389
447
390
448
391
449
def astra_projection_geometry (geometry ):
@@ -435,6 +493,22 @@ def astra_projection_geometry(geometry):
435
493
vec = astra_conebeam_2d_geom_to_vec (geometry )
436
494
proj_geom = astra .create_proj_geom ('fanflat_vec' , det_count , vec )
437
495
496
+ elif isinstance (geometry , ParallelVecGeometry ) and geometry .ndim == 2 :
497
+ det_count = geometry .detector .size
498
+ vec = geometry .vectors
499
+ # TODO: flip axes?
500
+ if not astra_supports ('parallel2d_vec_geometry' ):
501
+ raise NotImplementedError (
502
+ "'parallel_vec' geometry not supported by ASTRA "
503
+ 'v{}' .format (ASTRA_VERSION ))
504
+ proj_geom = astra .create_proj_geom ('parallel_vec' , det_count , vec )
505
+
506
+ elif isinstance (geometry , ConeVecGeometry ) and geometry .ndim == 2 :
507
+ det_count = geometry .detector .size
508
+ vec = geometry .vectors
509
+ # TODO: flip axes?
510
+ proj_geom = astra .create_proj_geom ('fanflat_vec' , det_count , vec )
511
+
438
512
elif (isinstance (geometry , ParallelBeamGeometry ) and
439
513
isinstance (geometry .detector , FlatDetector ) and
440
514
geometry .ndim == 3 ):
@@ -452,6 +526,23 @@ def astra_projection_geometry(geometry):
452
526
vec = astra_conebeam_3d_geom_to_vec (geometry )
453
527
proj_geom = astra .create_proj_geom ('cone_vec' , det_row_count ,
454
528
det_col_count , vec )
529
+
530
+ elif isinstance (geometry , ParallelVecGeometry ) and geometry .ndim == 3 :
531
+ det_row_count = geometry .det_partition .shape [1 ]
532
+ det_col_count = geometry .det_partition .shape [0 ]
533
+ vec = geometry .vectors
534
+ # TODO: flip axes?
535
+ proj_geom = astra .create_proj_geom ('parallel3d_vec' , det_row_count ,
536
+ det_col_count , vec )
537
+
538
+ elif isinstance (geometry , ConeVecGeometry ) and geometry .ndim == 3 :
539
+ det_row_count = geometry .det_partition .shape [1 ]
540
+ det_col_count = geometry .det_partition .shape [0 ]
541
+ vec = geometry .vectors
542
+ # TODO: flip axes?
543
+ proj_geom = astra .create_proj_geom ('cone_vec' , det_row_count ,
544
+ det_col_count , vec )
545
+
455
546
else :
456
547
raise NotImplementedError ('unknown ASTRA geometry type {!r}'
457
548
'' .format (geometry ))
0 commit comments