Bug fixed with detail injection where exposure compensation was wrongly applied and killing hdr data

This commit is contained in:
sumitchatterjee13
2025-10-04 09:45:52 +10:00
parent c14ab801cc
commit 3162cc3adc
+73 -47
View File
@@ -352,10 +352,16 @@ class DebevecHDRProcessor:
times = np.array(exposure_times, dtype=np.float32)
# ADAPTIVE AUTO-CALIBRATION for AI-generated images
if auto_calibrate and algorithm in ["debevec", "robertson"]:
logger.info("🔬 AUTO-CALIBRATION ENABLED for AI-generated brackets")
times_calibrated = np.array(self._calibrate_exposure_times(processed_images, times.tolist()), dtype=np.float32)
times = times_calibrated
# CRITICAL: Only apply for debevec and robertson algorithms
if auto_calibrate:
if algorithm in ["debevec", "robertson"]:
logger.info("🔬 AUTO-CALIBRATION ENABLED for AI-generated brackets")
times_calibrated = np.array(self._calibrate_exposure_times(processed_images, times.tolist()), dtype=np.float32)
times = times_calibrated
else:
logger.info(f"⚠️ Auto-calibrate is enabled but has NO EFFECT on '{algorithm}' mode (only works with debevec/robertson)")
else:
logger.info("Auto-calibration DISABLED")
logger.info(f"Processing {len(processed_images)} images with {algorithm} algorithm")
logger.info(f"Exposure times: {times}")
@@ -1210,56 +1216,76 @@ class DebevecHDRProcessor:
logger.info(" EV+4 extreme shadow injection complete")
# Step 4: Automatic Brightness Compensation
logger.info("\nStep 4: Automatic Brightness Compensation")
logger.info("\nStep 4: Automatic Brightness Compensation (HDR-Preserving)")
logger.info("-" * 40)
# Calculate current mean using 50th percentile (median) as reference
# This is more robust than mean for images with extreme values
result_flat = result.flatten()
# CRITICAL: Calculate brightness based ONLY on base range (0-1.0)
# This prevents HDR values from affecting brightness calculation
base_range_mask = result <= 1.0
base_range_pixels = result[base_range_mask]
# Calculate median across all channels
current_median = np.median(result_flat)
# Also calculate mean for comparison
current_mean = np.mean(result_flat)
# Target: 0.18 in linear space = 18% gray = professional middle gray
# For very dark images, use median-based scaling
# For normal images, use mean-based scaling
target_value = 0.18
logger.info(f" Current median: {current_median:.4f}")
logger.info(f" Current mean: {current_mean:.4f}")
logger.info(f" Target (18% gray): {target_value:.4f}")
# Use median if image is very dark (shadows dominate)
# Use mean if image has reasonable brightness distribution
if current_median < 0.05:
# Very dark image - use median for scaling
reference_value = current_median
logger.info(f" Using median-based scaling (image is very dark)")
else:
# Normal image - use mean for scaling
reference_value = current_mean
logger.info(f" Using mean-based scaling (normal brightness)")
if reference_value > 0.001: # Avoid division by zero
brightness_factor = target_value / reference_value
if base_range_pixels.size > 0:
current_median = np.median(base_range_pixels)
current_mean = np.mean(base_range_pixels)
# More permissive range for brightness adjustment (0.3x to 8.0x)
# This allows proper recovery of very dark or very bright images
brightness_factor = np.clip(brightness_factor, 0.3, 8.0)
# Target: 0.18 in linear space = 18% gray = professional middle gray
target_value = 0.18
if abs(brightness_factor - 1.0) > 0.05: # Only adjust if significant difference
logger.info(f" Applying brightness compensation: {brightness_factor:.3f}x")
result = result * brightness_factor
logger.info(f" New value range: [{result.min():.4f}, {result.max():.4f}]")
logger.info(f" New mean: {result.mean():.4f}")
logger.info(f" New median: {np.median(result):.4f}")
logger.info(f" Current median (base range): {current_median:.4f}")
logger.info(f" Current mean (base range): {current_mean:.4f}")
logger.info(f" Target (18% gray): {target_value:.4f}")
logger.info(f" HDR pixels (>1.0): {np.sum(result > 1.0)}")
# Use median if image is very dark (shadows dominate)
# Use mean if image has reasonable brightness distribution
if current_median < 0.05:
# Very dark image - use median for scaling
reference_value = current_median
logger.info(f" Using median-based scaling (image is very dark)")
else:
logger.info(" No brightness adjustment needed (already optimal)")
# Normal image - use mean for scaling
reference_value = current_mean
logger.info(f" Using mean-based scaling (normal brightness)")
if reference_value > 0.001: # Avoid division by zero
brightness_factor = target_value / reference_value
# More permissive range for brightness adjustment (0.3x to 8.0x)
# This allows proper recovery of very dark or very bright images
brightness_factor = np.clip(brightness_factor, 0.3, 8.0)
if abs(brightness_factor - 1.0) > 0.05: # Only adjust if significant difference
logger.info(f" Applying brightness compensation: {brightness_factor:.3f}x")
# CRITICAL: Apply compensation differently based on whether we're brightening or darkening
if brightness_factor >= 1.0:
# Brightening: Apply to ALL pixels including HDR (scales everything up)
result = result * brightness_factor
logger.info(f" Brightening mode: Applied to all pixels including HDR")
else:
# Darkening: Only darken base range (0-1.0), preserve HDR values
# HDR values represent recoverable highlight detail - we must preserve them!
hdr_mask = result > 1.0
hdr_values = result[hdr_mask].copy() # Save HDR values
# Apply darkening to base range
result = result * brightness_factor
# Restore HDR values (unscaled)
result[hdr_mask] = hdr_values
logger.info(f" Darkening mode: Applied to base range only, HDR values preserved")
logger.info(f" Preserved {np.sum(hdr_mask)} HDR pixels above 1.0")
logger.info(f" New value range: [{result.min():.4f}, {result.max():.4f}]")
logger.info(f" New mean (base range): {np.mean(result[result <= 1.0]):.4f}")
logger.info(f" New median (base range): {np.median(result[result <= 1.0]):.4f}")
logger.info(f" HDR pixels preserved: {np.sum(result > 1.0)}")
else:
logger.info(" No brightness adjustment needed (already optimal)")
else:
logger.warning(" Skipping brightness compensation (image too dark)")
else:
logger.warning(" Skipping brightness compensation (image too dark)")
logger.warning(" No base range pixels found for brightness compensation")
# Final statistics
logger.info("\nStep 5: Final Result Statistics (Linear HDR)")