surface_filter — ROUGHNESS prepare op

• Datenarten: depth → depth

• Aufruf: import fullseye as fs; fs.ledger.surface_filter(z, dx, lambda_c=None, lambda_s=None, kind='gaussian', end_effect='reject', dy=None) (die Implementierung direkt: import roughness; roughness.surface_filter(z, dx, lambda_c=None, lambda_s=None, kind='gaussian', end_effect='reject', dy=None); aus dem Register: opsroughness.get("surface_filter"))

• Rückgabewert über das Register: fullseye.ledger.surface_filter(...) liefert nur den Wert des deklarierten Out-Typs depth (die zugrunde liegende Funktion gibt zusätzlich Hilfsinformationen zurück). Wird das Verworfene gebraucht, nutze fullseye.ledger.surface_filter.raw(...) oder rufe roughness.surface_filter direkt auf.

• Rückgabe der Funktion: (roughness, waviness)

Verwendung

Zerlegt ein Höhenfeld in Rauheit und Welligkeit (Gauß-Filter nach ISO 16610-21).

Rückgabe ist (roughness, waviness). roughness ist der Anteil kürzer als λc, waviness der längere, und sofern nicht end_effect="reject", stimmt roughness + waviness exakt mit der Eingabe (der Primärfläche nach Anwendung von λs) überein.

Argumente

z Höhenfeld z[i, j] (Zeile = y, Spalte = x).

dx, dy Abtastabstände. dy=None bedeutet quadratische Pixel.

lambda_c langwellige Grenzwellenlänge (Grenze Rauheit / Welligkeit). Bei None keine Trennung

(waviness ist ein Null-Array).

lambda_s kurzwellige Grenzwellenlänge (S-Filter gegen Rauschen). Mit None deaktiviert.

kind nur "gaussian". Alles andere löst eine Ausnahme aus, statt stillschweigend ersetzt zu werden.

end_effect "reject" (Standard) / "mirror" / "wrap". Siehe unten.

dy Abtastabstand in Zeilenrichtung (None = dx).

★ Randbehandlung (end_effect) — der Grund, warum dieser op geschrieben wurde

Die Faltung braucht an den Rändern über den Kernradius (GAUSS_TRUNCATE·λc = 0.75 λc, 4 σ) hinweg "Daten von dort, wo keine sind".

Die Norm (ISO 16610-28) setzt voraus, dass der Auswertebereich an beiden Enden beschnitten wird.

• "reject" (Standard) — verwirft an beiden Enden ceil(0.75 λc/pitch) Abtastwerte. Die Ausgabe ist ein kleineres Array als die Eingabe. Der verworfene Bereich ist "nicht gemessen", daher ist dies die einzige Option ohne Lüge.

• "mirror" — setzt spiegelbildlich fort und gibt dieselbe Form zurück. Nimmt an, dass die Fläche an den Rändern eine gerade Funktion ist.

• "wrap" — zyklische Faltung (wie FFT). Nimmt an, dass auf das linke Ende das rechte Ende folgt.

Gemessen (★ die folgende Tabelle wurde mit der Kappung ±λc/2 gemessen, vor dem 2026-10-18. Nach der Erweiterung des Kerns auf ±0.75 λc

gelten 1.–3. unverändert; nur der Randstreifen wächst von 40 auf 60 Abtastwerte. Die Zahlen wurden nicht neu gemessen).

Die Ground Truth ist eine 704x704-Fläche, zuerst gefiltert und dann auf die mittleren 512x512 zugeschnitten

(die Antwort, berechnet mit echten Daten außerhalb der Ränder). dx=1, λc=80,

Randstreifen = äußere 40 Abtastwerte, dort beträgt der rms der Ground Truth 0.1932.

Flächenzustand end_effect rms-Fehler Randstreifen rms-Fehler Mitte

geneigt wrap 4.3883 (2272 %) 0.0e+00 (0.000 %)

geneigt mirror 0.1765 ( 91 %) 0.0e+00 (0.000 %)

Neigung entfernt wrap 0.0111 ( 5.7 %) 4.4e-15 (0.000 %)

Neigung entfernt mirror 0.0115 ( 5.9 %) 4.4e-15 (0.000 %)

(beliebig) reject — keine Rückgabe — 0.0e+00 (0.000 %)

4 Erkenntnisse:

1. Die Randbehandlung wirkt nur am Rand. Die Mitte stimmt bei allen exakt mit der Ground Truth überein (selbstverständlich, da der Kern die Ränder nicht erreicht, aber geprüft).

2. Die schlechteste Kombination ist "wrap mit verbliebener Neigung" — der Randfehler beträgt das 23-fache der Ground Truth selbst. Da angenommen wird, dass auf das linke Ende das rechte folgt, entsteht an der Nahtstelle der 2 unterschiedlich hohen Kanten eine Stufe.

3. Ist die Neigung entfernt, gibt es zwischen wrap und mirror keinen Unterschied (5.7 % gegen 5.9 %, wrap etwas besser). Nicht "zyklische Faltung ist immer schlecht", sondern "sie zu verwenden, ohne die Neigung zu entfernen, ist schlecht" ist richtig.

4. Der Preis von reject ist Fläche. Bei 512x512 und λc=80 werden 41.4 % verworfen (392x392 bleiben; bei der Kappung ±λc/2 waren es 28.8 %). Der verworfene Anteil wächst wie 1 - (1 - 1.5 λc/L)², sodass bei einem λc über 1/6 der Auswertelänge fast die Hälfte verloren geht.

★ Entspricht die Übertragung der Norm? (gemessen, λc=80, dx=1, Sinus mit ganzzahliger Periode per Projektion gemessen. Am 2026-10-18 korrigiert)

λ Welligkeit ISO-Normwert Differenz (Welligkeit / Differenz vor der Korrektur)

16 0.000030 0.000000 +3.0e-05 0.000806 / +8.1e-04

32 0.013094 0.013139 -4.5e-05 0.017206 / +4.1e-03

40 0.062544 0.062500 +4.4e-05 0.058676 / -3.8e-03

64 0.338531 0.338564 -3.3e-05 0.342826 / +4.3e-03

80 0.500012 0.500000 +1.2e-05 0.509549 / +9.6e-03 ← λc

128 0.762894 0.762799 +9.5e-05 0.772150 / +9.4e-03

256 0.934601 0.934550 +5.1e-05 0.937944 / +3.4e-03

Vor der Korrektur lag der Wert bei der Grenzwellenlänge selbst bei 0.5095 statt 0.5000 (relativ +1.9 %). Die Ursache war weder die Konstante α

(√(ln2/π)) noch die Normierung nach der Abtastung, sondern die Kappung ±λc/2 (= 2.67 σ) im Wortlaut der Norm: Sie lässt

0.8 % der Ausläufer wegfallen, und die Renormierung des Rests auf 1 vergrößert den Tiefpassanteil.

Mit der Kappung ±0.75 λc (4 σ) ergibt sich bei λc 0.500012, und der maximale Fehler über alle Wellenlängen fällt auf 9.5e-05 (Tabelle oben).

Der Preis: Der von reject verworfene Randstreifen wird 1.5-mal so breit. Die Summe aus Rauheit und Welligkeit stimmt in beiden Fällen exakt mit der Eingabe überein.

fail-closed

• kind nicht "gaussian" / end_effect keiner der 3 bekannten Werte.

• lambda_c und lambda_s beide None (ein Aufruf, der nichts tut).

• Grenzwellenlänge unter der Nyquist-Wellenlänge 2*pitch oder über der Messstrecke.

• lambda_s >= lambda_c (das Band wird leer).

• nach dem Beschneiden mit "reject" bleibt kein Array übrig.

Ausführlicher Anwendungsleitfaden

• Leitfaden zur Familie surface_roughness

Referenzen (Beispieldaten, Literatur)

• Katalog der Beispieldaten (Download-URLs / Lizenzen) — 2-D nutzt skimage.data (BSD/Public Domain) plus synthetische Bilder, 3-D nennt Download-URLs echter Datenquellen (Stanford, PDS, …).

• Herkunft und Literatur der Operatoren — die Quellen der Forschung/Verfahren, auf denen diese Operatorfamilie beruht.

• Der kanonische Algorithmus (Autor, Jahr) und seine Anwendungen stehen im Familienleitfaden oben.

Ausführbare Beispiele (verifizierte Samples, die diesen Operator wirklich aufrufen)

• poc_robust_profile_filter — py -3.11 examples/poc_robust_profile_filter.py

• poc_surface_roughness — py -3.11 examples/poc_surface_roughness.py

Typkompatible Folge-Operatoren (nehmen depth als Eingabe)

surface_form_remove · robust_gaussian_surface · surface_params · surface_psd

Gleiche Kategorie (prepare)

surface_form_remove · robust_gaussian_profile · robust_spline_profile · robust_gaussian_surface


*Provenance: roughness.py — ROUGHNESS Operator-Registry. Diese Notiz wird von tools/opdocs.py md erzeugt (nicht von Hand bearbeiten).*

© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.