Skip to content

Commit

Permalink
move detector shift to framework geometry
Browse files Browse the repository at this point in the history
  • Loading branch information
gfardell committed Sep 27, 2023
1 parent 8a1e3ab commit 39ef31e
Show file tree
Hide file tree
Showing 4 changed files with 126 additions and 22 deletions.
44 changes: 43 additions & 1 deletion Wrappers/Python/cil/framework/framework.py
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ def __init__ (self, dof):
@staticmethod
def create_vector(val):
try:
vec = numpy.asarray(val, dtype=numpy.float64).reshape(len(val))
vec = numpy.array(val, dtype=numpy.float64).reshape(len(val))
except:
raise ValueError("Can't convert to numpy array")

Expand Down Expand Up @@ -1982,6 +1982,48 @@ def configured(self):
configured = False
return configured

def shift_detector_in_plane(self,
pixel_offset,
direction='horizontal'):
"""
Adjusts the position of the detector in a specified direction within the imaging plane.
Parameters:
-----------
pixel_offset : float
The number of pixels to adjust the detector's position by.
direction : {'horizontal', 'vertical'}, optional
The direction in which to adjust the detector's position. Defaults to 'horizontal'.
Notes:
------
- If `direction` is 'horizontal':
- If the panel's origin is 'left', the detector's position is moved to the left.
- If the panel's origin is 'right', the detector's position is moved to the right.
- If `direction` is 'vertical':
- If the panel's origin is 'bottom', the detector's position is moved downward.
- If the panel's origin is 'top', the detector's position is moved upward.
Returns:
--------
None
"""

if direction == 'horizontal':
pixel_size = self.panel.pixel_size[0]
pixel_direction = self.system.detector.direction_x

elif direction == 'vertical':
pixel_size = self.panel.pixel_size[1]
pixel_direction = self.system.detector.direction_y

if 'bottom' in self.panel.origin or 'left' in self.panel.origin:
self.system.detector.position -= pixel_offset * pixel_direction * pixel_size
else:
self.system.detector.position += pixel_offset * pixel_direction * pixel_size


def __str__(self):
repres = ""
if self.configured:
Expand Down
14 changes: 3 additions & 11 deletions Wrappers/Python/cil/processors/Padder.py
Original file line number Diff line number Diff line change
Expand Up @@ -555,15 +555,13 @@ def _process_acquisition_geometry(self):
continue

offset = (self._pad_width_param[i][0] -self._pad_width_param[i][1])*0.5
system_detector = geometry.config.system.detector

if dim == 'channel':
geometry.set_channels(num_channels= geometry.config.channels.num_channels + \
self._pad_width_param[i][0] + self._pad_width_param[i][1])
elif dim == 'angle':
# extrapolate pre-values from a[1]-a[0]
# extrapolate post-values from a[-1]-a[-2]

a = self._geometry.angles
end_values = (
a[0]-(a[1]-a[0] )* self._pad_width_param[i][0],
Expand All @@ -574,19 +572,13 @@ def _process_acquisition_geometry(self):
elif dim == 'vertical':
geometry.config.panel.num_pixels[1] += self._pad_width_param[i][0]
geometry.config.panel.num_pixels[1] += self._pad_width_param[i][1]

if 'bottom' in geometry.config.panel.origin:
system_detector.position = system_detector.position - offset * system_detector.direction_y * geometry.config.panel.pixel_size[1]
else:
system_detector.position = system_detector.position + offset * system_detector.direction_y * geometry.config.panel.pixel_size[1]
geometry.config.shift_detector_in_plane(offset, dim)

elif dim == 'horizontal':
geometry.config.panel.num_pixels[0] += self._pad_width_param[i][0]
geometry.config.panel.num_pixels[0] += self._pad_width_param[i][1]
if 'left' in geometry.config.panel.origin:
system_detector.position = system_detector.position - offset * system_detector.direction_x * geometry.config.panel.pixel_size[0]
else:
system_detector.position = system_detector.position + offset * system_detector.direction_x * geometry.config.panel.pixel_size[0]
geometry.config.shift_detector_in_plane(offset, dim)

return geometry

def _process_image_geometry(self):
Expand Down
12 changes: 2 additions & 10 deletions Wrappers/Python/cil/processors/Slicer.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,6 @@ def _process_acquisition_geometry(self):
Creates the new acquisition geometry
"""
geometry_new = self._geometry.copy()
system_detector = geometry_new.config.system.detector

processed_dims = self._processed_dims.copy()

Expand All @@ -283,11 +282,7 @@ def _process_acquisition_geometry(self):
if n_elements > 1:
# difference in end indices, minus differences in start indices, divided by 2
pixel_offset = ((self._shape_in[vert_ind] -1 - self._pixel_indices[vert_ind][1]) - self._pixel_indices[vert_ind][0])*0.5
if 'bottom' in geometry_new.config.panel.origin:
system_detector.position = system_detector.position - pixel_offset * system_detector.direction_y * geometry_new.config.panel.pixel_size[1]
else:
system_detector.position = system_detector.position + pixel_offset * system_detector.direction_y * geometry_new.config.panel.pixel_size[1]

geometry_new.config.shift_detector_in_plane(pixel_offset, 'vertical')
geometry_new.config.panel.num_pixels[1] = n_elements
else:
try:
Expand Down Expand Up @@ -319,10 +314,7 @@ def _process_acquisition_geometry(self):
elif axis == 'horizontal':
pixel_offset = ((self._shape_in[i] -1 - self._pixel_indices[i][1]) - self._pixel_indices[i][0])*0.5

if 'left' in geometry_new.config.panel.origin:
system_detector.position = system_detector.position - pixel_offset * system_detector.direction_x * geometry_new.config.panel.pixel_size[0]
else:
system_detector.position = system_detector.position + pixel_offset * system_detector.direction_x * geometry_new.config.panel.pixel_size[0]
geometry_new.config.shift_detector_in_plane(pixel_offset, axis)
geometry_new.config.panel.num_pixels[0] = n_elements
geometry_new.config.panel.pixel_size[0] *= roi.step

Expand Down
78 changes: 78 additions & 0 deletions Wrappers/Python/test/test_AcquisitionGeometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,84 @@ def test_create_Cone3D(self):
np.testing.assert_allclose(AG.config.system.rotation_axis.position, rotation_axis_position, rtol=1E-6)
np.testing.assert_allclose(AG.config.system.rotation_axis.direction, rotation_axis_direction, rtol=1E-6)


def test_shift_detector_origin_bottom_left(self):
initial_position = np.array([2.5, -1.3, 10.2])
pixel_size = np.array([0.5, 0.7])
detector_direction_x=np.array([1/math.sqrt(2),0,1/math.sqrt(2)])
detector_direction_y=np.array([-1/math.sqrt(2),0,1/math.sqrt(2)])

geometry = AcquisitionGeometry.create_Parallel3D(detector_position=initial_position, detector_direction_x=detector_direction_x, detector_direction_y=detector_direction_y)\
.set_panel([10, 5], [0.5, 0.7], origin='bottom-left')\
.set_angles([0])
# Test horizontal shift to the left
shift = -1.5
geometry.config.shift_detector_in_plane(shift, 'horizontal')
updated_position = geometry.config.system.detector.position
expected_position = initial_position - detector_direction_x * pixel_size[0] * shift
np.testing.assert_array_almost_equal(updated_position, expected_position)

# Test horizontal shift to the right
shift = 3.0
geometry.config.shift_detector_in_plane(shift, 'horizontal')
updated_position = geometry.config.system.detector.position
expected_position = expected_position - detector_direction_x * pixel_size[0] * shift
np.testing.assert_array_almost_equal(updated_position, expected_position)

# Test vertical shift down
shift = -1.5
geometry.config.shift_detector_in_plane(shift, 'vertical')
updated_position = geometry.config.system.detector.position
expected_position = expected_position - detector_direction_y * pixel_size[1] * shift
np.testing.assert_array_almost_equal(updated_position, expected_position)

# Test vertical shift up
shift = 3.0
geometry.config.shift_detector_in_plane(shift, 'vertical')
updated_position = geometry.config.system.detector.position
expected_position = expected_position - detector_direction_y * pixel_size[1] * shift
np.testing.assert_array_almost_equal(updated_position, expected_position)


def test_shift_detector_origin_top_right(self):
initial_position = np.array([2.5, -1.3, 10.2])
detector_direction_x=np.array([1/math.sqrt(2),0,1/math.sqrt(2)])
detector_direction_y=np.array([-1/math.sqrt(2),0,1/math.sqrt(2)])

pixel_size = np.array([0.5, 0.7])
geometry = AcquisitionGeometry.create_Parallel3D(detector_position=initial_position, detector_direction_x=detector_direction_x, detector_direction_y=detector_direction_y)\
.set_panel([10, 5], [0.5, 0.7], origin='top-right')\
.set_angles([0])

# Test horizontal shift to the right
shift = -1.5
geometry.config.shift_detector_in_plane(shift, 'horizontal')
updated_position = geometry.config.system.detector.position
expected_position = initial_position + detector_direction_x * pixel_size[0] * shift
np.testing.assert_array_almost_equal(updated_position, expected_position)

# Test horizontal shift to the left
shift = 3.0
geometry.config.shift_detector_in_plane(shift, 'horizontal')
updated_position = geometry.config.system.detector.position
expected_position = expected_position + detector_direction_x * pixel_size[0] * shift
np.testing.assert_array_almost_equal(updated_position, expected_position)

# Test vertical shift up
shift = -1.5
geometry.config.shift_detector_in_plane(shift, 'vertical')
updated_position = geometry.config.system.detector.position
expected_position = expected_position + detector_direction_y * pixel_size[1] * shift
np.testing.assert_array_almost_equal(updated_position, expected_position)

# Test vertical shift down
shift = 3.0
geometry.config.shift_detector_in_plane(shift, 'vertical')
updated_position = geometry.config.system.detector.position
expected_position = expected_position + detector_direction_y * pixel_size[1] * shift
np.testing.assert_array_almost_equal(updated_position, expected_position)


def test_SystemConfiguration(self):

#SystemConfiguration error handeling
Expand Down

0 comments on commit 39ef31e

Please sign in to comment.