11#include " tone_mapping.hpp"
22#include < cstring>
33#include < memory>
4+ #include < algorithm>
45
56// Tone mapping constants
67constexpr float MIN_LUMA_THRESHOLD = 0 .001f ; // Threshold to avoid division by near-zero luminance
7- constexpr float REINHARD_LUMINANCE_SCALE = 1 .2f ; // Gentle luminance boost before tone mapping
8+ constexpr float REINHARD_LUMINANCE_SCALE = 0 .85f ; // Moderate compression for HDR content
9+
10+ // Helper function to calculate luminance from RGB using Rec.709 coefficients
11+ static inline float calculate_luminance (float r, float g, float b) {
12+ return 0 .2126f * r + 0 .7152f * g + 0 .0722f * b;
13+ }
814
915cv::Mat* apply_hdr_to_sdr_tone_mapping (
1016 const cv::Mat* src,
@@ -66,6 +72,31 @@ cv::Mat* apply_hdr_to_sdr_tone_mapping(
6672 src_for_transform = bgr_only.get ();
6773 }
6874
75+ // Analyze image brightness to adaptively tune tone mapping scale
76+ // Calculate average luminance across the image
77+ float total_luma = 0 .0f ;
78+ int pixel_count = src_for_transform->rows * src_for_transform->cols ;
79+
80+ for (int y = 0 ; y < src_for_transform->rows ; y++) {
81+ const uint8_t * src_row = src_for_transform->ptr <uint8_t >(y);
82+ for (int x = 0 ; x < src_for_transform->cols ; x++) {
83+ int idx = x * 3 ;
84+ float b = src_row[idx + 0 ] / 255 .0f ;
85+ float g = src_row[idx + 1 ] / 255 .0f ;
86+ float r = src_row[idx + 2 ] / 255 .0f ;
87+ total_luma += calculate_luminance (r, g, b);
88+ }
89+ }
90+ float avg_brightness = total_luma / pixel_count;
91+
92+ // Adaptive scale factor: brighter images get more compression (lower scale)
93+ // Map brightness [0.0-1.0] to scale [0.85-1.1]
94+ // Very bright images (0.7+) get compression (0.85-0.92)
95+ // Moderate images (0.3-0.7) get balanced treatment (0.92-1.02)
96+ // Dark images (0.0-0.3) get slight boost (1.02-1.1)
97+ float adaptive_scale = 1 .1f - (avg_brightness * 0 .25f );
98+ adaptive_scale = std::max (0 .85f , std::min (1 .1f , adaptive_scale));
99+
69100 // Apply Reinhard tone mapping
70101 // Tried to use OpenCV's built in tone mapping, but ran into issues with
71102 // dimming blown out/deep fried images. Using this as a first pass
@@ -85,10 +116,10 @@ cv::Mat* apply_hdr_to_sdr_tone_mapping(
85116 float r = src_row[idx + 2 ] / 255 .0f ;
86117
87118 // Calculate luminance using Rec.709 coefficients
88- float luma = 0 . 2126f * r + 0 . 7152f * g + 0 . 0722f * b ;
119+ float luma = calculate_luminance (r, g, b) ;
89120
90- // Apply gentle Reinhard tone mapping to luminance only
91- float luma_scaled = luma * REINHARD_LUMINANCE_SCALE ;
121+ // Apply Reinhard tone mapping to luminance only with adaptive scale
122+ float luma_scaled = luma * adaptive_scale ;
92123 float luma_mapped = luma_scaled / (1 .0f + luma_scaled);
93124
94125 // Scale RGB channels by the luminance ratio to preserve color
0 commit comments