IDS peak ICV v1.4.0
Loading...
Searching...
No Matches
High Dynamic Range

High Dynamic Range (HDR) imaging is a technique used to reconstruct an image that preserves detail in both the darkest and brightest regions of a scene. Traditional Low Dynamic Range (LDR) images — such as standard 8‑bit images — can only represent a limited intensity range. This often results in loss of detail in shadows and highlights.

Examples include:

  • Interior photographs with bright windows
  • Sunlit outdoor scenes
  • Night scenes with bright artificial lights
  • Industrial inspection images with highly reflective surfaces

By combining multiple exposures captured at different exposure values (for example, −2 EV, 0 EV, and +2 EV), HDR reconstruction synthesizes a single image that preserves detail across a wider dynamic range.

The HDR class and accompanying HDRAlgorithm enum provide a high‑level interface for performing such reconstruction using the Debevec and Malik method.

Core Concepts

Exposure Bracketing

HDR requires multiple images of the same static scene captured with different exposure times. Only exposure should change — focus, aperture, and camera position must remain stable.

Camera Response Curve (CRC)

Most HDR algorithms estimate a mapping between scene radiance and pixel intensities. This mapping is the camera response curve. In the Debevec method, estimating the CRC is a radiometric calibration step that helps accurately reconstruct scene radiance.

Radiance Map

After calibration, all pixel intensities from input images can be merged into a unified physical quantity called the radiance map — the nonlinear mapping that relates pixel intensities to scene irradiance. This radiance map forms the basis of the final HDR image. The map typically uses floating‑point precision to accommodate very wide dynamic ranges.

Tone Mapping

Although not explicitly part of the provided class, HDR images usually must be tone‑mapped for display on standard monitors (which cannot display full HDR radiance ranges). Tone mapping is performed as a separate step.

Requirements

Images

To perform HDR reconstruction, you need the following:

  • Same scene across all exposures
  • Images should be well‑aligned
  • Same resolution and pixel format
  • Only exposure changes
  • At least two images (three or more recommended)

Example Results

Exposure: 1000µs Exposure: 4000µs LDR Image
EV: 1000 EV: 4000 LDR Image

Usage instructions

This example demonstrates a complete HDR workflow — from calibration to tone mapping — and annotates each step with the why behind the what.

  • C++
    std::vector<peak::icv::Image> calibrationImages = GetCalibrationImages();
    const auto calibrationExposureTimes = GetCalibrationExposureTimesMicroseconds();
    for (size_t i = 0; i < calibrationImages.size(); ++i)
    {
    auto metaData = calibrationImages[i].GetMetadata();
    metaData.SetValueByKey<peak::common::MetadataKey::DeviceExposureTime>(calibrationExposureTimes[i]);
    calibrationImages[i].SetMetadata(metaData);
    }
    hdr.EstimateResponseCurve(calibrationImages);
    std::vector<peak::icv::Image> processingImages = GetProcessingImages();
    const auto processExposureTimes = GetProcessExposureTimesMicroseconds();
    for (size_t i = 0; i < processingImages.size(); ++i)
    {
    auto metaData = processingImages[i].GetMetadata();
    metaData.SetValueByKey<peak::common::MetadataKey::DeviceExposureTime>(processExposureTimes[i]);
    processingImages[i].SetMetadata(metaData);
    }
    peak::icv::Image hdrImage = hdr.Process(processingImages);
    peak::icv::Image ldrImage = toneMapping.Process(hdrImage);
  • C#
    using var hdr = new Hdr();
    //
    using var calibrationImages = GetCalibrationImages();
    var calibrationExposureTimes = GetExposureTimesCalibrationMicroSeconds();
    foreach (var pair in calibrationImages.Zip(calibrationExposureTimes, (image, exposure) => new { image, exposure }))
    {
    var metadata = pair.image.Metadata;
    metadata.SetValueByKey(MetadataKeys.DeviceExposureTime, pair.exposure);
    pair.image.Metadata = metadata;
    }
    //
    hdr.EstimateResponseCurve(calibrationImages);
    //
    using var processingImages = GetProcessingImages();
    var processingExposureTimes = GetExposureTimesProcessMicroSeconds();
    foreach (var pair in processingImages.Zip(processingExposureTimes, (image, exposure) => new { image, exposure }))
    {
    var metadata = pair.image.Metadata;
    metadata.SetValueByKey(MetadataKeys.DeviceExposureTime, pair.exposure);
    pair.image.Metadata = metadata;
    }
    using var hdrImage = hdr.Process(processingImages);
    //
    using var toneMapping = new DragoToneMapping();
    using var ldrImage = toneMapping.Process(hdrImage);
  • Python
    hdr = HDR()
    calibration_images = get_calibration_images()
    for image, exposure_time in zip(calibration_images, get_calibration_exposure_times_microseconds()):
    metadata = image.metadata
    metadata.set_value_by_key(MetadataKey.DEVICE_EXPOSURE_TIME, exposure_time)
    image.metadata = metadata
    hdr.estimate_response_curve(calibration_images)
    processing_images = get_processing_images()
    for image, exposure_time in zip(processing_images, get_process_exposure_times_microseconds()):
    metadata = image.metadata
    metadata.set_value_by_key(MetadataKey.DEVICE_EXPOSURE_TIME, exposure_time)
    image.metadata = metadata
    hdr_image = hdr.process(processing_images)
    tone_mapping = DragoToneMapping()
    ldr_image = tone_mapping.process(hdr_image)

Create an HDR object

Creating the HDR object sets the reconstruction algorithm to Debevec and prepares internal state. Currently, only the Debevec algorithm is supported.

Take exposure‑bracketed images

Estimating the camera response curve (CRC) and HDR reconstruction requires a set of multi‑exposure images of the same static scene.

The exposure times should be staggered logarithmically to ensure that all intensity levels are well represented. The user must ensure that each image is associated with the correct exposure time in its metadata, as incorrect or mismatched values will lead to invalid calibration results.

The resulting image sequence must be provided as an array (see the API Reference for the expected type).

EV: 500µs EV: 1000µs EV: 4000µs EV: 8000µs

Estimate the camera response curve

Calling the estimate_response_curve function performs the radiometric calibration step required by the HDR algorithm. During this operation, the system evaluates the provided multi‑exposure images and collects representative pixel samples across all exposure levels. It then solves the optimization system to estimate the camera response curve. The computed CRC is cached internally for use in the processing step.

To store the CRC persistantly, it can be serialized to a file and later deserialized:

Reconstruct radiance map

The process function performs the actual HDR reconstruction by combining the exposure‑bracketed input images into a high‑dynamic‑range radiance map. Using the previously estimated CRC, the algorithm first linearizes all pixel intensities so they represent proportional scene irradiance. It then evaluates each pixel location across all exposures, applies the Debevec–Malik weighting scheme to suppress unreliable values (such as saturated highlights or underexposed shadows), and solves for the corresponding radiance value. The result is a floating‑point radiance map that preserves detail across the full brightness range of the scene. Only pixels with reliable values are inside the resulting image region.

If the camera response curve was not estimated explicitly, the process function automatically esimates the curve during its first call, which increases the total processing time.

Tone map the radiance map

After HDR reconstruction, the resulting radiance map typically contains a much wider range of luminance values than standard displays can reproduce. To convert this high-dynamic-range data into a displayable format, the library provides specialized tone mapping operators (e.g., Drago or Linear), which compress the HDR image into a low-dynamic-range (LDR) representation.

For more details on the available operators, see the language-specific modules:

During this operation, the algorithm maps floating‑point radiance values into the output range (typically 8‑bit or 16‑bit per channel). This step produces an LDR image suitable for visualization and saving.