Rausch-Explorer — gaussian / uniform / poisson, nebeneinander, live

Interaktiver Vergleich der drei Verteilungen der nativen addNoise-Op. Ein 1×5-Streifen zeigt das Original neben gaussian (Rauschen mit konstantem σ), uniform (flach ±σ), poisson (signalabhängiges Schrotrauschen — Lichter verrauschter, Schatten sauber) und COMBINED — der realistische „Endoutput": ein Luminanz-Gauss-Pass mit schwächerem Per-Kanal-Poisson-Chroma-Pass darüber, so wie man addNoise tatsächlich für überzeugendes Sensorrauschen stapelt. //!LIVE ist an, der SIGMA-Regler aktualisiert alle fünf Panels gleichzeitig; der COLOR-Schalter wechselt die drei Primitive zwischen gemeinsamem Luminanz-Korn und Per-Kanal-Chroma-Rauschen. addNoise ist das Degradations-Primitiv hinter samples/binaries/degrade.js.

INPUT
INPUT — Rausch-Explorer — gaussian / uniform / poisson, nebeneinander, live
original | gaussian | uniform | poisson | combined
original | gaussian | uniform | poisson | combined — Rausch-Explorer — gaussian / uniform / poisson, nebeneinander, live
JavaScript
// Interactive noise explorer — the three addNoise distributions plus
// a realistic COMBINED stack. With //!LIVE on, dragging SIGMA updates
// all five panels at once, so the character of each is easy to compare.
// demo_noise.js
//!INPUT: INPUT
//!OUTPUT: OUTPUT
//!PARAM: SIGMA:number=0.08,min=0,max=0.3,step=0.005
//!PARAM: COLOR:boolean=false
//!PARAM: DETAIL:integer=420,min=0,max=4096
//!PARAM: SEED:integer=1,min=0,max=1000000
// SEED: gleiche Zahl → gleiches Rauschen (reproduzierbar); 0 → jedes Mal neu.
//!LIVE: true,debounce=120

// `addNoise` is the native degradation primitive (see also
// samples/binaries/degrade.js). Three distributions:
//
//   gaussian — additive normal noise, constant σ. The classic
//              sensor read-noise.
//   uniform  — flat noise in ±σ. Harsher, no tail.
//   poisson  — shot noise: σ scales with √pixel, so highlights get
//              noisier and shadows stay clean. The most photographic.
//
// COLOR off → one sample shared across RGB (luminance grain);
// COLOR on  → each channel independent (chroma noise).
//
// COMBINED is the "end output" — how you'd actually use addNoise for
// realistic degradation: a luminance pass (gaussian, mono) with a
// weaker chroma pass on top (poisson, color). Real sensor noise has
// both components, so stacking them looks far more convincing than
// any single distribution alone. The COLOR toggle does not affect
// this panel — it always demonstrates the mono+color stack.

// Ausschnitt statt Verkleinerung: Rauschen ist ein Pixel-Phaenomen. Wuerde man die fertige Tafel
// herunterskalieren, mittelte man genau das weg, was hier zu sehen
// sein soll. DETAIL = 0 nimmt das ganze Bild.
const loaded = Engine.loadImage(INPUT);
let orig = loaded;
if (DETAIL > 0 && loaded.width > DETAIL) {
  const cw = Math.min(DETAIL, loaded.width);
  const ch = Math.min(Math.round(DETAIL * loaded.height / loaded.width), loaded.height);
  orig = loaded.clone().crop(
    Math.round((loaded.width - cw) / 2),
    Math.round((loaded.height - ch) / 2),
    cw, ch);
  loaded.free();
}
const W = orig.width, H = orig.height;

const noised = (type) =>
    orig.clone().addNoise({ type, sigma: SIGMA, color: COLOR, seed: SEED || undefined });

const gaussian = noised("gaussian");
const uniform  = noised("uniform");
const poisson  = noised("poisson");

// COMBINED — realistic sensor-noise stack: luminance grain first,
// then a weaker independent-channel chroma pass on top.
const combined = orig.clone()
    .addNoise({ type: "gaussian", sigma: SIGMA, color: false, seed: SEED || undefined })
    .addNoise({ type: "poisson", sigma: SIGMA * 0.6, color: true, seed: SEED ? SEED + 1 : undefined });

// 3×2-Raster: original + die drei Grundarten + das kombinierte
// Ergebnis. Nicht 1×5, weil eine Galerie ihre Bilder auf Spaltenbreite
// bringt — eine Reihe aus fuenf Feldern wird dort so schmal, dass vom
// Korn nichts uebrig bleibt. Bei drei Spalten bleibt jedes Feld
// lesbar, und das sechste Fach traegt die Einstellung, mit der die
// Reihe erzeugt wurde.
const panels = [
    ["ORIGINAL", orig],
    ["GAUSSIAN", gaussian],
    ["UNIFORM",  uniform],
    ["POISSON",  poisson],
    ["COMBINED", combined],
];
const COLS_N = 3;
const ROWS_N = Math.ceil((panels.length + 1) / COLS_N);
const sheet = Engine.createImage(1, 1);
sheet.setPixel(px(0, 0), new Pixel(0.05, 0.05, 0.07, 1));
sheet.resize(W * COLS_N, H * ROWS_N);
const ink = new Pixel(1, 1, 1, 0.85);
panels.forEach(([label, img], i) => {
    const x0 = (i % COLS_N) * W;
    const y0 = Math.floor(i / COLS_N) * H;
    sheet.blendAt(img, px(x0, y0), 1.0);
    sheet.drawText(label, x0 + 16, y0 + 34, { font: "JetBrains Mono", size: 24, color: ink });
});

// Freies Fach: die Einstellung, die zu diesen Feldern gehoert.
const lastX = (panels.length % COLS_N) * W;
const lastY = Math.floor(panels.length / COLS_N) * H;
sheet.drawText(`sigma ${SIGMA}`, lastX + 16, lastY + 40,
    { font: "JetBrains Mono", size: 28, color: ink });
sheet.drawText(COLOR ? "color noise" : "mono noise", lastX + 16, lastY + 78,
    { font: "JetBrains Mono", size: 20, color: ink });

sheet.save(OUTPUT);

sheet.free();
gaussian.free();
uniform.free();
poisson.free();
combined.free();
orig.free();

`addNoise σ=${SIGMA} ${COLOR ? "color" : "mono"} — gaussian | uniform | poisson | combined`;

// © 2026 Michael Lechner · mlc OpticScript · https://mlcgo.eu · Elastic License 2.0