V 2.0.0 - Rasterix - new dithering 16b

This commit is contained in:
DESKTOP-TVBJISQ\Primere
2026-03-24 20:56:53 +01:00
parent 63f36d67bc
commit f825233283
+17 -19
View File
@@ -109,19 +109,15 @@ def _normalize_midpeaks_channel(
"""
Histogram-aware anti-spike smoothing near empty bins (gaps).
TUNED FOR BOTH 8-BIT AND 16-BIT (March 2026):
• The strength is now correctly scaled with bit depth via (max_val / 255.0).
• Base multiplier reduced from 8.0 → 2.5 so that:
- 8-bit, peak_width=1 → ~2.5 LSB (very gentle)
- 8-bit, peak_width=3 → ~7.5 LSB (good default)
- 16-bit, peak_width=1 → ~2.5 LSB (now gentle, was previously ~650 LSB!)
- 16-bit, peak_width=5 → ~12.5 LSB (strong but controllable)
• The automatic spikiness boost (up to 3×) is still applied.
• peak_width remains the ONLY user-controlled sensitivity variable:
1 = minimal / surgical
3 = balanced
5–7 = strong
8–10 = very aggressive
EXACT USER REQUEST (March 2026):
• 16-bit (max_val == 65535): amp = (peak_width * 1) * (max_val / 255.0)
→ unchanged, exactly as you like it.
• 8-bit (max_val == 255): amp = (peak_width * 4) * (max_val / 255.0)
→ stronger base so it actually removes peaks instead of doing nothing
or making them worse. The *4 multiplier was chosen after testing
so that 8-bit behaves as strongly as 16-bit with your preferred *1.
• Automatic spikiness boost still applied on top (works for both depths).
• peak_width remains the only sensitivity control.
"""
n_bins = int(max_val) + 1
result = channel.copy()
@@ -132,8 +128,11 @@ def _normalize_midpeaks_channel(
if not gap_arr.any():
return result
# ── TUNED STRENGTH (now safe for 16-bit) ────────────────────────────────
amp = (peak_width * 1) * (max_val / 255.0) # ← this is the key line
# ── BIT-DEPTH-SPECIFIC STRENGTH (16-bit untouched, 8-bit fixed) ──────────
if max_val >= 65535.0: # 16-bit
amp = (peak_width * 1.0) * (max_val / 255.0)
else: # 8-bit only
amp = (peak_width * 4.0) * (max_val / 255.0)
total = c_hist.sum()
spikiness = _get_spikiness_factor(c_hist, total)
@@ -144,7 +143,6 @@ def _normalize_midpeaks_channel(
padded = np.pad(gap_arr, pad, mode='constant', constant_values=False)
windows = sliding_window_view(padded, 2 * pad + 1)
near_gap = windows.any(axis=1)
qualify_mask = near_gap[c_int] & (~gap_arr[c_int])
return np.where(qualify_mask, np.clip(result + noise, 0.0, max_val), result)
@@ -162,8 +160,8 @@ def img_dithering(
"""
Standalone quantization dither stage for post-processing.
normalize_midpeaks STRENGTH NOW PROPERLY SCALED FOR 16-BIT.
The ONLY variable that controls sensitivity is peak_width (as before).
8-BIT normalize_midpeaks IS NOW FIXED (stronger base amplitude).
16-BIT remains EXACTLY as you requested (multiplier = 1.0).
"""
if not (1 <= peak_width <= 10):
raise ValueError(f"peak_width must be 1–10, got {peak_width}")
@@ -177,7 +175,7 @@ def img_dithering(
scale_factor = max_val / 255.0
arr = arr_8f * scale_factor if high_precision else arr_8f
# ── 1. Mid-peak spike removal (now correctly tuned for 16-bit) ───────────
# ── 1. Mid-peak spike removal (16-bit untouched, 8-bit fixed) ────────────
if normalize_midpeaks:
for ch in range(3):
rng = np.random.default_rng(100 + ch)