Source code for visionsim.emulate.rgb

from __future__ import annotations

from typing import cast

import numpy as np
import numpy.typing as npt

from visionsim.utils.color import linearrgb_to_srgb


[docs] def emulate_rgb_from_sequence( sequence: npt.ArrayLike, readout_std: float = 20.0, fwc: float = 500.0, bitdepth: int = 12, factor: float = 1.0, rng: np.random.Generator | None = None, ) -> npt.NDArray: """Emulates a conventional RGB camera from a sequence of intensity frames. Note: Motion-blur is approximated by averaging consecutive ground truth frames, this can be done more efficiently if optical flow is available. See `emulate_rgb_from_flow` for more. Args: sequence (npt.ArrayLike): Input sequence of linear-intensity frames, can be a collection of frames, or np/torch array with time as the first dimension. readout_std (float, optional): Standard deviation of zero mean Gaussian read noise. Defaults to 20.0. fwc (float, optional): Full well capacity, used for normalization. Defaults to 500.0. bitdepth (int, optional): Resolution of ADC in bits. Defaults to 12. factor (float, optional): Scaling factor to control intensity of output RGB image. Defaults to 1.0. rng (np.random.Generator, optional): Optional random number generator. Defaults to none. Returns: Quantized sRGB patch is returned """ # Get sum of linear-intensity frames. sequence = np.array(sequence) burst_size = len(sequence) patch = np.sum(sequence, axis=0) * factor # Perform poisson sampling and add zero-mean gaussian read noise rng = np.random.default_rng() if rng is None else rng patch = cast(npt.NDArray, rng.poisson(patch)).astype(float) patch += rng.normal(0, readout_std * burst_size / 255.0, size=patch.shape) # Normalize by full well capacity, clip highlights, and quantize to 12-bits patch = np.clip(patch / fwc, 0, 1.0) patch = np.round(patch * (2**bitdepth - 1)) / (2**bitdepth - 1) # Multiply by gain to keep constant(-ish) brightness patch *= fwc / (burst_size * factor) # Convert to sRGB color space for viewing and quantize to 8-bits patch = linearrgb_to_srgb(patch) patch = np.round(patch * 2**8) / 2**8 return patch
[docs] def emulate_rgb_from_flow(): """Not (Yet) Implemented""" raise NotImplementedError