V 2.0.0 - Rasterix - new dithering 16b
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user