|
53 | 53 | from odl.discr import DiscreteLp, DiscreteLpElement
|
54 | 54 | from odl.tomo.geometry import (
|
55 | 55 | Geometry, DivergentBeamGeometry, ParallelBeamGeometry, FlatDetector)
|
| 56 | +from odl.tomo.util.utility import euler_matrix |
56 | 57 | from odl.util.utility import pkg_supports
|
57 | 58 |
|
58 | 59 |
|
@@ -165,17 +166,21 @@ def astra_volume_geometry(discr_reco):
|
165 | 166 | 'non-isotropic pixels in 2d volumes not supported by ASTRA '
|
166 | 167 | 'v{}'.format(ASTRA_VERSION))
|
167 | 168 | # Given a 2D array of shape (x, y), a volume geometry is created as:
|
168 |
| - # astra.create_vol_geom(y, x, x_min, x_max, y_min, y_max) |
| 169 | + # astra.create_vol_geom(x, y, y_min, y_max, x_min, x_max) |
169 | 170 | # yielding a dictionary:
|
170 |
| - # {'GridRowCount': y, |
171 |
| - # 'GridColCount': x, |
172 |
| - # 'WindowMinX': x_min, |
173 |
| - # 'WindowMaxX': x_max, |
174 |
| - # 'WindowMinY': y_min, |
175 |
| - # 'WindowMaxY': y_max} |
176 |
| - vol_geom = astra.create_vol_geom(vol_shp[1], vol_shp[0], |
177 |
| - vol_min[0], vol_max[0], |
178 |
| - vol_min[1], vol_max[1]) |
| 171 | + # {'GridRowCount': x, |
| 172 | + # 'GridColCount': y, |
| 173 | + # 'WindowMinX': y_min, |
| 174 | + # 'WindowMaxX': y_max, |
| 175 | + # 'WindowMinY': x_min, |
| 176 | + # 'WindowMaxY': x_max} |
| 177 | + # |
| 178 | + # NOTE: this setting is flipped with respect to x and y. We do this |
| 179 | + # as part of a global rotation of the geometry by -90 degrees, which |
| 180 | + # avoids rotating the data. |
| 181 | + vol_geom = astra.create_vol_geom(vol_shp[0], vol_shp[1], |
| 182 | + vol_min[1], vol_max[1], |
| 183 | + vol_min[0], vol_max[0]) |
179 | 184 | elif discr_reco.ndim == 3:
|
180 | 185 | # Not supported in all versions of ASTRA
|
181 | 186 | if (not discr_reco.partition.has_isotropic_cells and
|
@@ -300,19 +305,24 @@ def astra_conebeam_2d_geom_to_vec(geometry):
|
300 | 305 | .. _ASTRA projection geometry documentation:
|
301 | 306 | http://www.astra-toolbox.com/docs/geom3d.html#projection-geometries
|
302 | 307 | """
|
| 308 | + # Instead of rotating the data by 90 degrees counter-clockwise, |
| 309 | + # we subtract pi/2 from the geometry angles, thereby rotating the |
| 310 | + # geometry by 90 degrees clockwise |
| 311 | + rot_minus_90 = euler_matrix(-np.pi / 2) |
303 | 312 | angles = geometry.angles
|
304 | 313 | vectors = np.zeros((angles.size, 6))
|
305 | 314 |
|
306 | 315 | for ang_idx, angle in enumerate(angles):
|
307 | 316 | # Source position
|
308 |
| - vectors[ang_idx, 0:2] = geometry.src_position(angle) |
| 317 | + vectors[ang_idx, 0:2] = rot_minus_90.dot(geometry.src_position(angle)) |
309 | 318 |
|
310 | 319 | # Center of detector
|
311 | 320 | mid_pt = geometry.det_params.mid_pt
|
312 |
| - vectors[ang_idx, 2:4] = geometry.det_point_position(angle, mid_pt) |
| 321 | + vectors[ang_idx, 2:4] = rot_minus_90.dot( |
| 322 | + geometry.det_point_position(angle, mid_pt)) |
313 | 323 |
|
314 | 324 | # Vector from detector pixel 0 to 1
|
315 |
| - det_axis = geometry.det_axis(angle) |
| 325 | + det_axis = rot_minus_90.dot(geometry.det_axis(angle)) |
316 | 326 | px_size = geometry.det_partition.cell_sides[0]
|
317 | 327 | vectors[ang_idx, 4:6] = det_axis * px_size
|
318 | 328 |
|
@@ -413,7 +423,10 @@ def astra_projection_geometry(geometry):
|
413 | 423 | # TODO: change to parallel_vec when available
|
414 | 424 | det_width = geometry.det_partition.cell_sides[0]
|
415 | 425 | det_count = geometry.detector.size
|
416 |
| - angles = geometry.angles |
| 426 | + # Instead of rotating the data by 90 degrees counter-clockwise, |
| 427 | + # we subtract pi/2 from the geometry angles, thereby rotating the |
| 428 | + # geometry by 90 degrees clockwise |
| 429 | + angles = geometry.angles - np.pi / 2 |
417 | 430 | proj_geom = astra.create_proj_geom('parallel', det_width, det_count,
|
418 | 431 | angles)
|
419 | 432 |
|
|
0 commit comments