# High Dynamic Range Image: Chunk and Paired Processed Implementation

Daniel Eduardo Ruiz

► To cite this version:

Daniel Eduardo Ruiz. High Dynamic Range Image: Chunk and Paired Processed Implementation. 2024. hal-04787006

HAL Id: hal-04787006

https://hal.science/hal-04787006v1

Preprint submitted on 16 Nov 2024

HAL is a multi-disciplinary open access
archive for the deposit and dissemination of sci-
entific research documents, whether they are pub-
lished or not. The documents may come from
teaching and research institutions in France or
abroad, or from public or private research centers.

L'archive ouverte pluridisciplinaire HAL, est
destinée au dépôt et à la diffusion de documents
scientifiques de niveau recherche, publiés ou non,
émanant des établissements d'enseignement et de
recherche français ou étrangers, des laboratoires
publics ou privés.

<figure><img src="image_1.png" /></figure>

Distributed under a Creative Commons Attribution 4.0 International License
High Dynamic Range Image:
Chunk and Paired Processed Implementation

Daniel Eduardo Ruiz

November 16, 2024

Abstract

This paper presents an implementation of High Dynamic Range (HDR) imaging using GPU acceleration. The algorithm combines multiple exposure images through vector angle calculations and weighted averaging, with special consideration for color differences and exposure weights. The implementation includes memory-efficient chunk processing and color balance adjustment techniques. We present a detailed mathematical framework for each normalization step and discuss the theoretical foundations of the weighting schemes.

# 1 Introduction

High Dynamic Range imaging aims to capture the full range of light intensity in a scene by combining multiple exposures. Our implementation leverages GPU acceleration through CuPy to process large images efficiently while maintaining high quality results. The algorithm employs a novel approach combining angular relationships between color vectors and weighted averaging with multiple normalization steps.

# 2 Mathematical Framework

The article is based on the article of exposure fusion see [2].

## 2.1 Vector Angle Calculation and Normalization

For two RGB vectors $\vec{a}$ and $\vec{b}$ from different exposures, we first apply a normalization shift to avoid zero-division:

$$ \vec{a}' = \vec{a} + 1, \quad \vec{b}' = \vec{b} + 1 \qquad (1) $$

We then calculate their angular relationship using the normalized dot product:
$$ \cos(\theta) = \frac{\vec{a}' \cdot \vec{b}'}{|\vec{a}'||\vec{b}'|} = \frac{r_1 r_2 + g_1 g_2 + b_1 b_2}{\sqrt{(r_1^2 + g_1^2 + b_1^2)(r_2^2 + g_2^2 + b_2^2)}} \quad (2) $$

The weighted combination of pixels includes a normalization step:

$$ \vec{P}_{\text{combined}} = \frac{\vec{a}' + \cos(\theta)\vec{b}'}{1 + \cos(\theta)} - 1 \quad (3) $$

The final subtraction of 1 reverses the initial normalization shift.

## 2.2 Exposure Weighting System

The exposure weight for each pixel employs a multi-step normalization process:

1. Initial Gaussian weighting:

$$ w_{\text{exp}} = e^{-\frac{(p-\mu)^2}{2\sigma^2}} \quad (4) $$

where $\mu = 128$ and $\sigma = 51$

2. Channel-wise product normalization:

$$ w_{\text{total}} = w_{\text{exp,r}} \cdot w_{\text{exp,g}} \cdot w_{\text{exp,b}} \quad (5) $$

## 2.3 Color Difference Weight and Normalization

The color difference weight includes both calculation and normalization steps:

$$ d_{\text{color}} = (r - g)^2 + (g - b)^2 + (b - r)^2 \quad (6) $$

Normalization through clipping:

$$ w_{\text{color}} = \text{clip}(d_{\text{color}}, 64, 192) \quad (7) $$

The final weight combines exposure and color components:

$$ w_{\text{final}} = w_{\text{total}} \cdot w_{\text{color}} \quad (8) $$

## 2.4 HDR Fusion and Normalization

For n input images, the HDR fusion process follows:

$$ P_{\text{HDR}} = \frac{\sum_{i=1}^{n} w_i \vec{P}_i}{\sum_{i=1}^{n} w_i} - 1 \quad (9) $$
## 3 Color Balance Adjustment

The final stage includes a sophisticated color balance adjustment:

1. Mean calculation per channel:

$$ \mu_{rgb} = \frac{r + g + b}{3} \qquad (10) $$

2. Channel-specific adjustment matrix:

$$ A = \begin{bmatrix} \mu_{rgb} \\ \mu_{rgb} \\ 1.2\mu_{rgb} \end{bmatrix} \qquad (11) $$

3. Final normalized adjustment:

$$ P_{final} = 2P_{HDR} - A \qquad (12) $$

## 4 Memory Management and Chunk Processing

The implementation processes images in chunks to optimize GPU memory usage. For an image of size $W \times H$, the chunked processing follows:

$$ N_{chunks} = \left\lfloor \frac{W}{chunk\_size} \right\rfloor \times \left\lfloor \frac{H}{chunk\_size} \right\rfloor \qquad (13) $$

Each chunk undergoes independent processing with border handling:

$$ chunk_{size,actual} = \min(chunk\_size, W - x_{start}) \times \min(chunk\_size, H - y_{start}) \qquad (14) $$

## 5 Algorithm Implementation

## 6 Implementation Code

This section presents the fully documented implementation of the HDR algorithm based on the Git Hub original code see [3]. The code is implemented in Python using CuPy for GPU acceleration.

### 6.1 Code Structure

The implementation consists of three main functions:

1. `calculate_angle`: Computes angular relationships between exposure pairs

2. `hdr`: Implements the core HDR fusion algorithm

3. `hdr_cpc`: Manages chunked processing and memory
<caption>**Algorithm 1** HDR Processing Pipeline with Normalization</caption>

1: **procedure** PROCESSHDR/images[])
2:     **for** each chunk in image **do**
3:         Normalize input vectors (+1 shift)
4:         Calculate angular weights between pairs
5:         Apply Gaussian exposure weighting
6:         Compute color difference weights
7:         Normalize combined weights
8:         Apply color balance adjustment
9:         Denormalize result (-1 shift)
10:     **end for**
11:   Concatenate chunks **return** final HDR image
12: **end procedure**

## 6.2 Angular Calculation Implementation

<caption>Listing 1: Vector Angle Calculation</caption>

```python
import cupy as cp
import numpy as np

def calculate_angle(img_a, img_b):
    """
    Calculate the angle between two RGB vectors and their weighted
    combination.

    """
    # Normalization shift to avoid division by zero
    img_a, img_b = img_a + 1, img_b + 1

    # Split into RGB channels
    r, g, b = img_a[: : ,0], img_a[: : ,1], img_a[: : ,2]
    r1, g1, b1 = img_b[: : ,0], img_b[: : ,1], img_b[: : ,2]

    # Calculate cosine of angle between vectors
    # Implements equation (2) from mathematical framework
    coef = (r1*r + g1*g + b1*b) / (
        cp.power(r1*r1 + g1*g1 + b1*b1, 0.5) *
        cp.power(r*r + g*g + b*b, 0.5)
    )

    # Stack coefficient for all channels
    coef = cp.stack([coef, coef, coef], axis=-1)

    # Weighted combination using equation (3)
    result = (img_a + coef*img_b)/(1 + coef) - 1
```
34
35

return result

6.3 HDR Fusion Implementation

<caption>Listing 2: HDR Fusion Core Algorithm</caption>

1 def hdr(*args):
2 """  
3 Create HDR image from multiple exposures using weighted averaging.
4 
5 
6 
7 
8 
9 
10 weighted_sum, weight_sum = 0, 0
11 
12 
13 
14 # Process each exposure
15 for img in args:
16 # Normalization shift
17 img = img + 1
18 
19 # Calculate exposure weight using Gaussian function
20 # Implements equation (4)
21 exp_weight = cp.exp(-1 * cp.power(img - 128, 2) /
22                      (2 * 51 * 51))
23 r, g, b = exp_weight[:3, :3], exp_weight[:3, 3], exp_weight
24 #: 2]
25 
26 # Channel-wise weight multiplication
27 weight = r * g * b
28 
29 # Calculate color difference weight
30 # Implements equations (5) and (6)
31 r, g, b = img[:3, :3], img[:3, 3], img[3, 3]
32 color_diff = (cp.power(r-g, 2) +
33               cp.power(g-b, 2) +
34               cp.power(b-r, 2))
35 
36 # Normalize color difference weight
37 color_diff = cp clipped color_diff, 64, 192
38 
39 # Combine weights
40 weight = weight * color_diff
41 weight = cpstack([weight, weight, weight], axis=-1)
42 
43 # Accumulate weighted sum
44 weighted_sum = weighted_sum + weight * img
45 weight_sum = weight_sum + weight
46 
47 # Normalize and adjust range
48 # Implements equation (7)
```python
result = weighted_sum/weight_sum - 1

# Color balance adjustment
# Implements equations (8), (9), and (10)
r, g, b = result[:3, :3], result[:3, 1], result[1, 1]
mean = (r + g + b)/3
mean = cpstack([mean, mean, 1.2*mean], axis=-1)
result = 2*result - mean

return result
```

## 6.4 Chunked Processing Implementation

<caption>Listing 3: Memory-Efficient Chunk Processing</caption>

```python
def hdrCP(chunk_size, img_1, img_2, img_3, img_4):
    """
    Process HDR images in chunks using GPU acceleration.
    """
    # Returns:
    # Processed HDR image as numpy array
    """
    height, width, _ = img_1.shape

    # Process image in square chunks
    for y in range(0, height + 1, chunk_size):
        for x in range(0, width + 1, chunk_size):
            # Calculate chunk boundaries
            x1 = min(x + chunk_size, width - 1)
            y1 = min(y + chunk_size, height - 1)

            # Extract chunks from all images
            chunk1 = img_1[x:x1, y:y1, 0:3]
            chunk2 = img_2[x:x1, y:y1, 0:3]
            chunk3 = img_3[x:x1, y:y1, 0:3]
            chunk4 = img_4[x:x1, y:y1, 0:3]

            # Process first angle calculation
            cp1 = cp.array(chunk1, hrefival=32)
            cp4 = cp.array(chunk4, hrefival=32)
            angle_result1 = calculate_angle(cp1, cp4)
            angle_result1 NP = np.array(angle_result1, hrefival=32)

            # Process second angle calculation
            cp2 = cp.array(chunk2, hrefival=32)
            cp3 = cp.array(chunk3, hrefival=32)
            angle_result2 = calculate_angle(cp2, cp3)
```
```python
# Combine results using HDR
angle_result1 = cp.array(angle_result1 np,
                          dtype=cp.float32)
hdr_result = hdr(angle_result1, angle_result2)

# Convert back to numpy array
hdr_result np = np.array(hdr_result.get(),
                        
dtype= np.float32)

# Concatenate chunks horizontally
if x == 0:
    row_result = hdr_result np
else:
    row_result = np
    (row_result, img_result np), axis=0)

# Concatenate rows vertically
if y == 0:
    final_result = row_result
else:
    final_result = np
    (final_result, row_result), axis=1)

return final_result
```

# 7 Saving image

<caption>Listing 4: Saving in .jpg format</caption>

```python
from PIL import Image

def img_a (paths):
    dir1, dir2, dir3, dir4 = paths
    img1 = np.array (Image.open (dir1)).astype (np. float32)
    img2 = np. array (Image.open (dir2)).astype (np. float32)
    img3 = np. array (Image.open (dir3)).astype (np. float32)
    img4 = np. array (Image.open (dir4)).astype (np. float32)

    aux img = img cp (1024, img1, img2, img3, img4)
    img = Image. fromarray (np. clip (aux img, 0, 255).astype (np.
    uint8))
    img.save(' img.jpg')
```

# 8 Experimental Results

We present the results of our HDR implementation using a test image set captured under varying exposure conditions available on [1]. The test scene includes both high-contrast and subtle detail areas to demonstrate the algorithm's effectiveness in Figure 1, Figure 2, Figure 3, Figure 4, Figure 5 and Figure 6.
<figure><img src="image_2.png" /><figcaption>(a) Low Exposure</figcaption></figure>

<figure><img src="image_3.png" /><figcaption>(b) Medium Exposure</figcaption></figure>

<figure><img src="image_4.png" /><figcaption>(c) High Exposure</figcaption></figure>

<figure><img src="image_5.png" /><figcaption>(d) High Exposure 2</figcaption></figure>

<figure><img src="image_6.png" /><figcaption>Figure 2: Final HDR result showing enhanced dynamic range</figcaption></figure>
<figure><img src="image_7.png" /><figcaption>Figure 3: Input images at different exposure levels.</figcaption></figure>

<figure><img src="image_8.png" /><figcaption>Figure 4: Final HDR result showing enhanced dynamic range</figcaption></figure>
<figure><img src="image_9.png" /><figcaption>Figure 5: Input images at different exposure levels.</figcaption></figure>

<figure><img src="image_10.png" /><figcaption>Figure 6: Final HDR result showing enhanced dynamic range</figcaption></figure>

References

[1] HDRsoft. Bracketed photos samples, 2024. Accessed: 2024-11-15.
[2] Tom Mertens, Jan Kautz, and Frank Van Reeth. Exposure fusion. In *Proceedings - Pacific Conference on Computer Graphics and Applications*, 2007.

[3] Daniel Eduardo Ruiz. algoritmooj_hdr_cupy.py, 2024. GitHub. Accesed: 15 de noviembre de 2024.