Malerischer Look, der der Bildstruktur folgt — anisotropic Kuwahara
`img.anisotropicKuwahara(radius)` ist die struktur-bewusste Variante von `kuwahara(radius)`. Gleicher Vier-Quadranten- Kern („glattester gewinnt"), aber jeder Pixel-Quadrant wird in die lokale Kantenrichtung gedreht (berechnet aus dem geglätteten Struktur-Tensor des Helligkeitsgradienten). Pinselstriche folgen der Bildtextur — Haare entlang der Haare, Stoffrippen entlang der Rippen — statt überall dasselbe kleine Quadrat zu sein. Kosten ~3× die klassische Variante. Lohnt sich, wenn Struktur wichtig ist: Porträts mit markantem Haar, Landschaften mit fließenden Linien. Bei sehr glattem Inhalt ist der Unterschied zu `kuwahara` gering. `RADIUS` 4-6 = feine Skizze, 8-12 = klares Gemälde (Standard), 16-20 = breite Striche.
INPUT
Anisotropic Kuwahara
JavaScript
// Painterly look that follows image structure — anisotropic Kuwahara
// demo_anisotropic_kuwahara.js
//!INPUT: INPUT
//!OUTPUT: OUTPUT
//!PARAM: RADIUS:integer=10,min=2,max=24
//!PARAM: SATURATION_BOOST:number=1.10,min=0.5,max=2.0
//!PARAM: SHARPEN_AMOUNT:number=0.20,min=0,max=2
// `img.anisotropicKuwahara(radius)` orients its four Kuwahara
// quadrants by the local edge direction — derived from the
// smoothed structure tensor of the luminance gradient. Compared
// to the classical `kuwahara(radius)` (axis-aligned quadrants),
// this version's brush strokes follow image texture: hair runs
// along hair, fabric ridges along ridges, instead of all being
// the same little square everywhere.
//
// Cost is ~3× the classical Kuwahara at the same radius (extra
// gradient + tensor smoothing pass), but the result reads as
// closer to a real painting in regions with strong directional
// structure. For very flat content (clear sky, plain skin) the
// difference vs. classical is subtle.
//
// Tweak guide:
// RADIUS = 4-6 → fine sketch / watercolour
// RADIUS = 8-12 → clear painterly look (default)
// RADIUS = 16-20 → broad strokes / gouache style
const img = Engine.loadImage(INPUT);
img.anisotropicKuwahara(RADIUS);
if (SATURATION_BOOST !== 1.0) {
img.saturation(SATURATION_BOOST);
}
if (SHARPEN_AMOUNT > 0) {
img.sharpen(SHARPEN_AMOUNT);
}
img.save(OUTPUT);
img.free();
// © 2026 Michael Lechner · mlc OpticScript · https://mlcgo.eu · Elastic License 2.0