Source code for httomolib.misc.rescale

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# ---------------------------------------------------------------------------
# Copyright 2023 Diamond Light Source Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either ecpress or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ---------------------------------------------------------------------------
# Created By  : Tomography Team at DLS <scientificsoftware@diamond.ac.uk>
# Created Date: 21 Aug 2025
# ---------------------------------------------------------------------------
"""Module for data rescaling."""

import numpy as np
from typing import Literal, Optional, Tuple, Union

from httomolib_c.modules import (
    rescale_to_int_8bit_C,
    rescale_to_int_16bit_C,
    rescale_to_int_32bit_C,
)

__all__ = [
    "rescale_to_int",
]


[docs] def rescale_to_int( data: np.ndarray, perc_range_min: float = 0.0, perc_range_max: float = 100.0, bits: Literal[8, 16, 32] = 8, glob_stats: Optional[Tuple[float, float, float, int]] = None, ) -> np.ndarray: """ Rescales the data given as float32 type and converts it into the range of an unsigned integer type with the given number of bits. See more information in https://diamondlightsource.github.io/httomolibgpu/reference/methods_list/rescale/rescale_to_int.html Parameters ---------- data : np.ndarray Input data as a 3D numpy array perc_range_min: float, optional The lower cutoff point in the input data, in percent of the data range (defaults to 0). The lower bound is computed as min + perc_range_min/100*(max-min) perc_range_max: float, optional The upper cutoff point in the input data, in percent of the data range (defaults to 100). The upper bound is computed as min + perc_range_max/100*(max-min) bits: Literal[8, 16, 32], optional The number of bits in the output integer range (defaults to 8). Allowed values are: - 8 -> uint8 - 16 -> uint16 - 32 -> uint32 glob_stats: tuple, optional Global statistics of the full dataset (beyond the data passed into this call). It's a tuple with (min, max, sum, num_items). If not given, the min/max is computed from the given data. Returns ------- np.ndarray The original data, clipped to the range specified with the perc_range_min and perc_range_max, and scaled to the full range of the output integer type """ if data.ndim != 3: raise ValueError("The rescale to int function accepts 3D arrays only") if bits == 8: output_dtype: Union[type[np.uint8], type[np.uint16], type[np.uint32]] = np.uint8 elif bits == 16: output_dtype = np.uint16 else: output_dtype = np.uint32 # get the min and max integer values of the output type output_min = np.iinfo(output_dtype).min output_max = np.iinfo(output_dtype).max if not isinstance(glob_stats, tuple): min_value = float(np.min(data)) max_value = float(np.max(data)) else: min_value = glob_stats[0] max_value = glob_stats[1] range_intensity = max_value - min_value input_min = (perc_range_min * (range_intensity) / 100) + min_value input_max = (perc_range_max * (range_intensity) / 100) + min_value factor = np.float32(1.0) if (input_max - input_min) != 0.0: factor = np.float32((output_max - output_min) / (input_max - input_min)) if input_max == pow(2, 32): input_max -= 1 if bits == 8: return rescale_to_int_8bit_C( np.asarray(data, order="C"), input_min, input_max, factor ) elif bits == 16: return rescale_to_int_16bit_C( np.asarray(data, order="C"), input_min, input_max, factor ) else: return rescale_to_int_32bit_C( np.asarray(data, order="C"), input_min, input_max, factor )