diff --git a/Wrappers/Python/cil/framework/framework.py b/Wrappers/Python/cil/framework/framework.py index bd4615340a..9365c83d2b 100644 --- a/Wrappers/Python/cil/framework/framework.py +++ b/Wrappers/Python/cil/framework/framework.py @@ -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") @@ -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: diff --git a/Wrappers/Python/cil/processors/Padder.py b/Wrappers/Python/cil/processors/Padder.py index 18717044ba..73f71420b6 100644 --- a/Wrappers/Python/cil/processors/Padder.py +++ b/Wrappers/Python/cil/processors/Padder.py @@ -555,7 +555,6 @@ 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 + \ @@ -563,7 +562,6 @@ def _process_acquisition_geometry(self): 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], @@ -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): diff --git a/Wrappers/Python/cil/processors/Slicer.py b/Wrappers/Python/cil/processors/Slicer.py index 8c0b7b542a..8aceca3d17 100644 --- a/Wrappers/Python/cil/processors/Slicer.py +++ b/Wrappers/Python/cil/processors/Slicer.py @@ -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() @@ -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: @@ -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 diff --git a/Wrappers/Python/test/test_AcquisitionGeometry.py b/Wrappers/Python/test/test_AcquisitionGeometry.py index 8b48dca847..07b4f4e052 100644 --- a/Wrappers/Python/test/test_AcquisitionGeometry.py +++ b/Wrappers/Python/test/test_AcquisitionGeometry.py @@ -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