Unverified Commit 26630279 authored by Zhang, Chen's avatar Zhang, Chen Committed by GitHub
Browse files

Merge pull request #271 from ornlneutronimaging/IMG444_update_default_atol

[IMG444] atol can be inferred during 180 deg pair finding for sorted array
parents 7c6079da 0b7b8fb8
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -34,7 +34,7 @@ imars3d.backend.corrections.intensity\_fluctuation\_correction module
   :members:
   :undoc-members:
   :show-inheritance:
   :exclude-members: ct, air_pixels, max_workers, name, sigma, tqdm_class
   :exclude-members: ct, air_pixels, max_workers, name, sigma, tqdm_class, roi

imars3d.backend.corrections.ring\_removal module
------------------------------------------------
@@ -43,4 +43,4 @@ imars3d.backend.corrections.ring\_removal module
   :members:
   :undoc-members:
   :show-inheritance:
   :exclude-members: arrays, correction_range, kernel_size, max_workers, name, sub_division, tqdm_class, sinogram
   :exclude-members: arrays, correction_range, kernel_size, max_workers, name, sub_division, tqdm_class, sinogram, extreme_streak_iterations, extreme_detect_lambda, extreme_detect_size, extreme_replace_size, max_bin_iter_horizontal, bin_vertical, filter_strength, use_slices, slice_sizes, slice_step_sizes, denoise_indices
+7 −7
Original line number Diff line number Diff line
@@ -26,8 +26,8 @@ class find_rotation_center(param.ParameterizedFunction):
        array of angles in degrees or radians, which must match the order of arrays
    in_degrees: bool = True
        whether angles are in degrees or radians, default is True (degrees)
    atol_deg: float = 1e-3
        tolerance for the search of 180 deg paris, default is 0.1 degrees
    atol_deg: Optional[float] = None
        tolerance for the search of 180 deg paris, default is None ("auto")
    num_pairs: int = 1
        Number of pairs to look for. Specifying -1 means as many pairs as possible.
    max_workers: int = 0
@@ -46,8 +46,8 @@ class find_rotation_center(param.ParameterizedFunction):
    )
    in_degrees = param.Boolean(default=True, doc="whether angles are in degrees or radians, default is True (degrees)")
    atol_deg = param.Number(
        default=1e-3,
        doc="tolerance for the search of 180 deg paris, default is 0.1 degrees",
        default=None,
        doc="tolerance for the search of 180 deg paris, default is None (auto)",
    )
    num_pairs = param.Integer(
        default=1, bounds=(-1, None), doc="Number of pairs to look for. Specifying -1 means as many pairs as possible."
@@ -72,7 +72,7 @@ class find_rotation_center(param.ParameterizedFunction):
            arrays=params.arrays,
            angles=params.angles,
            in_degrees=params.in_degrees,
            atol_deg=params.atol_deg,
            atol=params.atol_deg,
            num_pairs=params.num_pairs,
            max_workers=self.max_workers,
            tqdm_class=params.tqdm_class,
@@ -85,7 +85,7 @@ class find_rotation_center(param.ParameterizedFunction):
        arrays: np.ndarray,
        angles: np.ndarray,
        in_degrees: bool = True,
        atol_deg: float = 1e-3,
        atol: float = None,
        num_pairs: int = 1,
        max_workers: int = -1,
        tqdm_class=None,
@@ -96,8 +96,8 @@ class find_rotation_center(param.ParameterizedFunction):
            logger.error(msg)
            raise ValueError(msg)
        # locate 180 degree pairs
        atol = atol_deg if in_degrees else np.radians(atol_deg)
        idx_low, idx_hgh = find_180_deg_pairs_idx(angles, atol=atol, in_degrees=in_degrees)
        # decide how many pairs to use
        if num_pairs <= 0 or num_pairs >= idx_low.size:
            logger.info("Using all pairs of angles")
        elif num_pairs == 1:
+10 −2
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ logger = logging.getLogger(__name__)

def find_180_deg_pairs_idx(
    angles: np.ndarray,
    atol: float = 1e-3,
    atol: float = None,
    in_degrees: bool = True,
) -> Tuple[np.ndarray, np.ndarray]:
    """
@@ -31,7 +31,7 @@ def find_180_deg_pairs_idx(
    angles:
        The list of angles as a 1d array.
    atol:
        The absolute tolerance in degree for the 180 degree pairs.
        The absolute tolerance for the 180 degree pairs.
    in_degrees:
        Whether the angles are in degrees or radians, default is in degrees.

@@ -45,6 +45,14 @@ def find_180_deg_pairs_idx(
        raise ValueError("angles must be a 1d array")
    # ensure angles are in degrees
    angles = angles if in_degrees else np.degrees(angles)
    # compute atol if not specified
    if atol is None:
        sorted_indices = np.argsort(angles)
        atol = np.min(np.diff(angles[sorted_indices])) / 2.0
        del sorted_indices
        logger.debug(f"use computed atol = {atol}")
    else:
        atol = atol if in_degrees else np.degrees(atol)
    # compute the self difference matrix
    angles = angles[..., np.newaxis]
    diff_matrix = angles.T - angles
+3 −0
Original line number Diff line number Diff line
@@ -72,10 +72,13 @@ def test_differrent_centers(center_ref):
    projs = get_synthetic_stack(center_ref)
    # this is using default number of pairs (1)
    center_calc = find_rotation_center(arrays=projs, angles=OMEGAS, in_degrees=False)
    # with atol
    center_calc2 = find_rotation_center(arrays=projs, angles=OMEGAS, in_degrees=False, atol=0.5)
    # verify
    # NOTE:
    # answer within the same pixel should be sufficient for most cases
    np.testing.assert_allclose(center_calc, center_ref, atol=0.2)
    np.testing.assert_allclose(center_calc2, center_ref, atol=0.2)


def test_wrong_dimension():
+7 −0
Original line number Diff line number Diff line
@@ -227,6 +227,13 @@ def test_find_180_deg_pairs():
    # verify
    np.testing.assert_equal(low_range_idx, np.array([0, 1, 2, 3, 4]))
    np.testing.assert_equal(high_range_idx, np.array([5, 6, 7, 8, 9]))
    # test explicit atol
    # NOTE: use the same formula to compute atol outside the function
    sorted_indices = np.argsort(omegas)
    atol = np.min(np.diff(omegas[sorted_indices])) / 2.0
    low_range_idx, high_range_idx = find_180_deg_pairs_idx(omegas, in_degrees=False, atol=atol)
    np.testing.assert_equal(low_range_idx, np.array([0, 1, 2, 3, 4]))
    np.testing.assert_equal(high_range_idx, np.array([5, 6, 7, 8, 9]))
    # test incorrect input
    omegas = np.random.random(5 * 5) * np.pi
    omegas = omegas.reshape(5, 5)