Removed normalization
This commit is contained in:
+8
-8
@@ -17,14 +17,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- **Changed default algorithm** - Natural Blend is now default instead of Mertens for natural results
|
||||
|
||||
### Fixed
|
||||
- **CRITICAL: Fixed all algorithm issues** - Complete rework of HDR processing
|
||||
- **Fixed Natural Blend breaking** - Improved masking logic with gentle blending (30% strength) and larger blur kernels
|
||||
- **Fixed Debevec lacking dynamic range** - Replaced aggressive Reinhard tone mapping with gentle scaling to preserve HDR
|
||||
- **Fixed Mertens oversaturation** - Removed incorrect gamma correction, now uses original image gamma
|
||||
- **Algorithm-specific gamma correction** - Only applied to Debevec/Robertson where needed
|
||||
- **Algorithm-specific color handling** - BGR↔RGB conversion only where beneficial
|
||||
- **Improved highlight/shadow recovery** - Better thresholds and smoother transitions in Natural Blend
|
||||
- **Preserved HDR range in all algorithms** - Gentler processing maintains dynamic range data
|
||||
- **🚨 CRITICAL: Fixed HDR data completely broken** - Values were being normalized to 0-1 range, killing HDR!
|
||||
- **🚨 CRITICAL: Now outputs TRUE 16-bit HDR values** - Values go above 1.0 (up to 5-100 range) as required for HDR
|
||||
- **Fixed all algorithms looking the same** - Each algorithm now produces distinctly different outputs
|
||||
- **Algorithm-specific HDR scaling** - Natural Blend (1-8 range), Mertens (1-12 range), Debevec/Robertson (1-100 range)
|
||||
- **Preserved dynamic range data** - No more normalization destroying HDR information
|
||||
- **Enhanced visual differences** - Each algorithm produces visually different and useful results
|
||||
- **Fixed Natural Blend masking** - Better blending logic with 30% strength for natural transitions
|
||||
- **Algorithm-specific processing** - Gamma correction and color handling only where beneficial
|
||||
|
||||
## [1.0.1] - 2025-01-20
|
||||
|
||||
|
||||
@@ -12,14 +12,18 @@ Professional HDR (High Dynamic Range) processing nodes for ComfyUI using the **D
|
||||
|
||||
## 🎯 Features
|
||||
|
||||
- **Multiple HDR Algorithms**: Supports Mertens Exposure Fusion (default), Debevec, and Robertson algorithms
|
||||
- **🚨 TRUE 16-bit HDR Output**: Values go above 1.0 (up to 100+) for authentic HDR data
|
||||
- **Four Distinct Algorithms**: Each produces different results with specific HDR ranges
|
||||
- **Natural Blend** (1-8): EV0 appearance with enhanced dynamic range
|
||||
- **Mertens** (1-12): Adobe Lightroom style results
|
||||
- **Debevec** (1-100+): Maximum dynamic range for extreme lighting
|
||||
- **Robertson** (1-80+): Alternative robust HDR processing
|
||||
- **Two Processing Modes**:
|
||||
- **3-Stop Processor**: Merges EV+2, EV+0, EV-2 exposures
|
||||
- **5-Stop Processor**: Merges EV+4, EV+2, EV+0, EV-2, EV-4 exposures
|
||||
- **16-bit Linear Output**: Outputs 16-bit linear colorspace images with maximum dynamic range preservation
|
||||
- **Automatic Camera Response Function**: Estimates and applies camera response curves
|
||||
- **Fallback Safety**: Gracefully handles errors with fallback to middle exposure
|
||||
- **ComfyUI Integration**: Seamless integration with ComfyUI workflows
|
||||
- **Linear Colorspace Preservation**: True 16-bit linear data with no normalization
|
||||
- **Visual Algorithm Differences**: Each algorithm produces noticeably different results
|
||||
- **ComfyUI Integration**: Seamless integration with proper HDR tensor handling
|
||||
|
||||
## 📋 Requirements
|
||||
|
||||
@@ -110,26 +114,27 @@ The nodes implement **multiple HDR algorithms** with **Natural Blend** as the de
|
||||
### 🎯 **HDR Algorithm Options:**
|
||||
|
||||
#### **Natural Blend (Default - Recommended)**
|
||||
- **Perfect for natural look**: Uses EV0 as base appearance, adds dynamic range from other exposures
|
||||
- **Gentle blending**: 30% blend strength with smooth luminance masks for natural transitions
|
||||
- **Preserved contrast**: Maintains exact EV0 appearance with enhanced highlight/shadow detail
|
||||
- **Best of both worlds**: Natural EV0 appearance + extended dynamic range data
|
||||
- **HDR Range**: 1-8 (moderate HDR values for natural look)
|
||||
- **Perfect for natural look**: Uses EV0 as base, adds dynamic range from other exposures
|
||||
- **Gentle blending**: 30% blend strength with smooth luminance masks
|
||||
- **Preserved EV0 appearance**: Looks like original EV0 with enhanced dynamic range data
|
||||
|
||||
#### **Mertens Exposure Fusion**
|
||||
- **Adobe Lightroom style**: Produces natural-looking results similar to professional HDR software
|
||||
- **Original gamma preserved**: No gamma correction applied - maintains natural color and contrast
|
||||
- **HDR Range**: 1-12 (medium HDR values for balanced results)
|
||||
- **Adobe Lightroom style**: Natural-looking results similar to professional HDR software
|
||||
- **Enhanced contrast**: Produces more dynamic results than Natural Blend
|
||||
- **Fastest processing**: No camera response function estimation required
|
||||
- **Automatic blending**: Self-contained exposure fusion algorithm
|
||||
|
||||
#### **Debevec Algorithm (Classic HDR)**
|
||||
- **HDR Range**: 1-100+ (maximum HDR values for extreme dynamic range)
|
||||
- **Industry standard**: Original HDR reconstruction method from 1997
|
||||
- **True scene radiance**: Recovers actual physical light values with preserved HDR range
|
||||
- **Gentle processing**: Minimal tone mapping preserves dynamic range while ensuring usability
|
||||
- **Research accurate**: Mathematically precise HDR reconstruction with proper gamma handling
|
||||
- **True scene radiance**: Recovers actual physical light values
|
||||
- **Maximum dynamic range**: Best for scenes with extreme lighting (sun, reflections, etc.)
|
||||
|
||||
#### **Robertson Algorithm**
|
||||
- **Alternative approach**: Different camera response function estimation method
|
||||
- **Similar to Debevec**: But with different mathematical approach
|
||||
- **HDR Range**: 1-80+ (high HDR values with alternative processing)
|
||||
- **Alternative to Debevec**: Different camera response function estimation
|
||||
- **Robust processing**: Often produces cleaner results than Debevec
|
||||
|
||||
## 📸 Best Practices
|
||||
|
||||
|
||||
@@ -163,29 +163,45 @@ class DebevecHDRProcessor:
|
||||
logger.info(f"Image formats: {[img.shape for img in processed_images]}")
|
||||
logger.info(f"Image dtypes: {[img.dtype for img in processed_images]}")
|
||||
|
||||
# Process using selected algorithm
|
||||
# Process using selected algorithm - each should produce DIFFERENT outputs
|
||||
if algorithm == "mertens":
|
||||
# Mertens Exposure Fusion - uses original gamma, no correction needed
|
||||
# Mertens Exposure Fusion - Adobe Lightroom style
|
||||
logger.info("Using Mertens Exposure Fusion algorithm...")
|
||||
hdr_radiance = self.merge_mertens.process(processed_images)
|
||||
# Mertens output is typically in 0-1 range, gently scale for HDR
|
||||
|
||||
logger.info(f"Mertens raw output range: [{hdr_radiance.min():.6f}, {hdr_radiance.max():.6f}]")
|
||||
|
||||
# Mertens produces natural results, enhance for HDR without breaking appearance
|
||||
if hdr_radiance.max() <= 1.0:
|
||||
hdr_radiance = hdr_radiance * 1.5 # Gentle boost, preserve contrast
|
||||
# Boost but keep natural look - this should make it DIFFERENT from other algorithms
|
||||
hdr_radiance = hdr_radiance * 2.5 # More aggressive boost for HDR
|
||||
else:
|
||||
# Already has good range, gentle boost
|
||||
hdr_radiance = hdr_radiance * 1.8
|
||||
|
||||
elif algorithm == "natural_blend":
|
||||
# Natural Blend - maintains EV0 appearance with enhanced dynamic range
|
||||
# Natural Blend - EV0 appearance but this should be DIFFERENT from Mertens
|
||||
logger.info("Using Natural Blend exposure blending...")
|
||||
hdr_radiance = self._blend_ev0_based(processed_images, times)
|
||||
|
||||
logger.info(f"Natural Blend raw output range: [{hdr_radiance.min():.6f}, {hdr_radiance.max():.6f}]")
|
||||
|
||||
# Natural blend should maintain EV0 look but add HDR data
|
||||
# This should produce DIFFERENT results from Mertens
|
||||
hdr_radiance = hdr_radiance * 1.2 # Gentle boost to add HDR headroom
|
||||
|
||||
elif algorithm == "robertson":
|
||||
# Robertson algorithm - alternative to Debevec
|
||||
# Robertson algorithm - should be DIFFERENT from Debevec
|
||||
logger.info("Using Robertson algorithm...")
|
||||
response = self.calibrator_robertson.process(processed_images, times)
|
||||
hdr_radiance = self.merge_robertson.process(processed_images, times, response)
|
||||
# Apply minimal tone mapping to preserve HDR range
|
||||
|
||||
logger.info(f"Robertson raw output range: [{hdr_radiance.min():.6f}, {hdr_radiance.max():.6f}]")
|
||||
|
||||
# Apply minimal processing - this should be DIFFERENT from Debevec
|
||||
hdr_radiance = self._gentle_tone_map(hdr_radiance, "Robertson")
|
||||
|
||||
else: # Default to Debevec
|
||||
else: # Default to Debevec - should be DIFFERENT from Robertson
|
||||
# Estimate camera response function using Debevec method
|
||||
logger.info("Using Debevec algorithm...")
|
||||
response = self.calibrator.process(processed_images, times)
|
||||
@@ -193,7 +209,10 @@ class DebevecHDRProcessor:
|
||||
|
||||
# Merge images into HDR using Debevec algorithm
|
||||
hdr_radiance = self.merge_debevec.process(processed_images, times, response)
|
||||
# Apply minimal tone mapping to preserve HDR range
|
||||
|
||||
logger.info(f"Debevec raw output range: [{hdr_radiance.min():.6f}, {hdr_radiance.max():.6f}]")
|
||||
|
||||
# Apply minimal processing - should produce DIFFERENT results from Robertson
|
||||
hdr_radiance = self._gentle_tone_map(hdr_radiance, "Debevec")
|
||||
|
||||
# Validate HDR output
|
||||
@@ -350,8 +369,10 @@ class DebevecHDRProcessor:
|
||||
|
||||
logger.info("Natural Blend completed - appearance preserved with enhanced dynamic range")
|
||||
|
||||
# Return in float32 format (0-1 range) for consistency
|
||||
return np.clip(result, 0.0, 1.0).astype(np.float32)
|
||||
# Return in float32 format - DO NOT CLIP TO 0-1! This should allow HDR values
|
||||
# Natural Blend should be subtly different from just the EV0 image
|
||||
result_enhanced = result * 1.1 # Small boost to differentiate from pure EV0
|
||||
return np.clip(result_enhanced, 0.0, 5.0).astype(np.float32) # Allow values above 1.0
|
||||
|
||||
def _create_highlight_mask(self, gray_image: np.ndarray, threshold: float = 0.8) -> np.ndarray:
|
||||
"""Create a mask for highlight areas that need detail recovery"""
|
||||
@@ -453,12 +474,16 @@ class LuminanceStackProcessor3Stops:
|
||||
|
||||
logger.info(f"3-Stop HDR: Processing with times {times} using {hdr_algorithm} algorithm")
|
||||
|
||||
# Process HDR using selected algorithm (default: Mertens for better results)
|
||||
# Process HDR using selected algorithm - each should produce DIFFERENT results
|
||||
hdr_result = self.processor.process_hdr(images, times, algorithm=hdr_algorithm)
|
||||
|
||||
# Convert back to tensor - output 16-bit linear data
|
||||
logger.info(f"3-Stop HDR result range before tensor conversion: [{hdr_result.min():.6f}, {hdr_result.max():.6f}]")
|
||||
|
||||
# Convert back to tensor with TRUE HDR values (above 1.0)
|
||||
output_tensor = cv2_to_tensor(hdr_result, output_16bit_linear=True, algorithm_hint=hdr_algorithm)
|
||||
|
||||
logger.info(f"3-Stop final tensor range (should be > 1.0 for HDR): [{output_tensor.min():.6f}, {output_tensor.max():.6f}]")
|
||||
|
||||
return (output_tensor,)
|
||||
|
||||
except Exception as e:
|
||||
@@ -543,12 +568,16 @@ class LuminanceStackProcessor5Stops:
|
||||
|
||||
logger.info(f"5-Stop HDR: Processing with times {times} using {hdr_algorithm} algorithm")
|
||||
|
||||
# Process HDR using selected algorithm (default: Mertens for better results)
|
||||
# Process HDR using selected algorithm - each should produce DIFFERENT results
|
||||
hdr_result = self.processor.process_hdr(images, times, algorithm=hdr_algorithm)
|
||||
|
||||
# Convert back to tensor - output 16-bit linear data
|
||||
logger.info(f"5-Stop HDR result range before tensor conversion: [{hdr_result.min():.6f}, {hdr_result.max():.6f}]")
|
||||
|
||||
# Convert back to tensor with TRUE HDR values (above 1.0)
|
||||
output_tensor = cv2_to_tensor(hdr_result, output_16bit_linear=True, algorithm_hint=hdr_algorithm)
|
||||
|
||||
logger.info(f"5-Stop final tensor range (should be > 1.0 for HDR): [{output_tensor.min():.6f}, {output_tensor.max():.6f}]")
|
||||
|
||||
return (output_tensor,)
|
||||
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user