asi_core.image.hdr.utils

This module provides utility functions of merging exposure series of all-sky images for high-dynamic range imaging.

Functions

remap_intensity_range(→ numpy.ndarray)

Linearly remap an image's intensity range [low_clip, high_clip] to [0, max_value_range].

normalize_image(image[, min_val, max_val])

Rescales an image to the range [0, 1].

tonemap_linear(→ numpy.ndarray)

Tone-map a linear HDR image to display-ready [0,1] range.

make_weight_lut(→ numpy.ndarray)

Return a (256,) weight lookup table in uint8 intensity domain [0..255].

compute_lne_bounds(→ Tuple[float, float])

Compute global lnE (log exposure) range from response curve and exposure times.

Module Contents

asi_core.image.hdr.utils.remap_intensity_range(image: numpy.ndarray, low_clip: int = 0, high_clip: int = 255, max_value_range: int = 255, dtype: numpy.dtype = np.uint8) numpy.ndarray

Linearly remap an image’s intensity range [low_clip, high_clip] to [0, max_value_range].

This function clips all pixel values below low_clip and above high_clip, then linearly rescales the remaining range to the specified output range (typically [0, 255] for 8-bit images).

Parameters:
  • image (numpy.ndarray) – Input 8-bit array of shape (H, W), (H, W, C), or (N, H, W, C).

  • low_clip (int) – Lower bound (inclusive) of the valid intensity range. Values below this threshold are clamped to 0. Default is 0.

  • high_clip (int) – Upper bound (inclusive) of the valid intensity range. Values above this threshold are clamped to max_value_range. Default is 255.

  • max_value_range (int) – Upper bound of the output domain (255 for 8-bit data).

  • dtype (np.dtype) – data type of remapped array. Default is np.uint8.

Raises:

AssertionError – If high_clip <= low_clip.

Returns:

Image remapped to the new intensity range as dtype in [0, max_value_range].

Return type:

numpy.ndarray

Note

  • This function can be used to remove unreliable tone ends for 8-bit JPEGs before calibration or HDR merging.

asi_core.image.hdr.utils.normalize_image(image, min_val=None, max_val=None)

Rescales an image to the range [0, 1].

The function normalizes the input image either using provided minimum and maximum values, or computes them from the image itself if not given.

Parameters:
  • image (numpy.ndarray) – Input image as a NumPy array.

  • min_val (float, optional) – Minimum value for rescaling (optional). If None, computed from image.

  • max_val (float, optional) – Maximum value for rescaling (optional). If None, computed from image.

Returns:

Normalized image with values between 0 and 1.

Return type:

numpy.ndarray

Raises:

ValueError – If max_val equals min_val, leading to division by zero.

asi_core.image.hdr.utils.tonemap_linear(hdr: numpy.ndarray, method: str = 'gamma', gamma: float = 2.2, exposure: float = 1.0, clip: bool = True) numpy.ndarray

Tone-map a linear HDR image to display-ready [0,1] range.

Parameters:
  • hdr (numpy.ndarray) – Linear HDR image (HxWxC or HxW), float32 or float64. Values are expected to be positive; they can exceed 1.0.

  • method (str) – Tone-mapping operator to use: - "gamma" : simple power-law gamma correction (default). - "reinhard": photographic tone reproduction. - "aces" : ACES filmic approximation.

  • gamma (float) – Gamma value for "gamma" method. Default is 2.2.

  • exposure (float) – Linear exposure multiplier applied before tone-mapping (use to brighten or darken the image globally). Default is 1.0.

  • clip (bool) – If True, clamp output to [0,1] range. Default is True.

Returns:

Tone-mapped image in [0,1] as float32.

Return type:

numpy.ndarray

Note

This function assumes the input HDR is linear. If your HDR is already gamma-encoded (e.g. from Mertens fusion), skip this step.

Examples:

# Basic gamma tone mapping
ldr = tonemap_linear(hdr, method="gamma", gamma=2.2)

# Reinhard operator with slight brightening
ldr = tonemap_linear(hdr, method="reinhard", exposure=1.2)
asi_core.image.hdr.utils.make_weight_lut(weight_type: str = 'triangle') numpy.ndarray

Return a (256,) weight lookup table in uint8 intensity domain [0..255].

Parameters:

weight_type (str) – Type of weight function to generate. Currently supports: - "triangle": Triangular weights centered at 127.5 (default). - "sine": Sine-based weights with cosine bump.

Returns:

Weight lookup table as a NumPy array of shape (256,) with dtype float32.

Return type:

numpy.ndarray

Raises:

ValueError – If an unsupported weight_type is specified.

asi_core.image.hdr.utils.compute_lne_bounds(response_curve: numpy.ndarray, exposure_times: numpy.ndarray) Tuple[float, float]

Compute global lnE (log exposure) range from response curve and exposure times.

The function calculates the minimum and maximum log exposure values based on the camera response curve and the corresponding exposure times.

Parameters:
  • response_curve (numpy.ndarray) – Camera response curve in logarithmic domain. Shape should be (256, 1, C) or (256, C), where C is the number of color channels.

  • exposure_times (numpy.ndarray) – Array of exposure times corresponding to each image in the series. Shape should be (N,), where N is the number of exposures.

Returns:

Tuple of (min_lnE, max_lnE), representing the global log exposure range.

Return type:

Tuple[float, float]

Note

This function assumes that the response_curve is in the logarithmic domain (g), and exposure_times are in linear units (e.g., seconds).