prepare op• Datenarten: depth → depth
• Aufruf: import fullseye as fs; fs.ledger.surface_form_remove(z, dx, order=1, method='ls', thresh=None, dy=None, iters=200, seed=0) (die Implementierung direkt: import roughness; roughness.surface_form_remove(z, dx, order=1, method='ls', thresh=None, dy=None, iters=200, seed=0); aus dem Register: opsroughness.get("surface_form_remove"))
• Rückgabewert über das Register: fullseye.ledger.surface_form_remove(...) 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_form_remove.raw(...) oder rufe roughness.surface_form_remove direkt auf.
• Rückgabe der Funktion: (residual, coeffs)
Entfernt eine Ebene / Fläche zweiter Ordnung direkt auf dem Gitter. Gibt (residual, coeffs) zurück.
Argumente
z Höhenfeld.
dx, dy Abtastabstände. dy=None bedeutet quadratische Pixel.
order 1 = Ebene, 2 = quadratische Fläche.
method "ls" (kleinste Quadrate) oder "ransac" (robust).
thresh RANSAC-Inlier-Schwelle (in Höheneinheiten). Bei None wird die robuste Streuung der Residuen der kleinsten Quadrate
2.5 x 1.4826 x MAD verwendet.
iters Anzahl der RANSAC-Versuche. Deterministisch über seed.
coeffs sind Monomkoeffizienten in physikalischen Koordinaten mit der Feldmitte als Ursprung. Bei order=1 sind es [c0, gx, gy], wobei gx/gy direkt der Gradient sind; bei order=2 sind es [c0, gx, gy, cxx, cxy, cyy] (in der Reihenfolge x^2, xy, y^2).
★ Warum das Gitter als Gitter übernommen wird
Die vorhandenen fit_plane / fit_plane_ransac akzeptieren nur (N,3)-Punktwolken.
Um ein 512²-Höhenfeld zu übergeben, muss es jedes Mal mit column_stack auf 262144x3 = 6.3 MB
expandiert werden (gemessen). Hier wird das Gitter als Gitter übernommen, und auch die Basis
wird aus äußeren Produkten von 1-D-Vektoren gebildet, sodass keine Expansion nötig ist.
★ Kosten (gemessen, 1024x1024, iters=200)
method="ls" 47 ms gegenüber method="ransac" 1.8 s (38-fach).
RANSAC zählt bei jedem Versuch die Residuen von 1024² Punkten neu, skaliert also linear mit iters.
Wer nur die Rauheit betrachtet, erhält mit "LS + λc-Hochpass" dieselbe Antwort zu 1/40 der Kosten
(siehe Messungen unten) — das ist der Grund, warum RANSAC nicht der Standard ist.
★ Falle — Robustheit braucht man nicht für "tiefe Kratzer", sondern für "breite Ausreißer".
Werden die Ausreißer jedoch zur Mehrheit, versagt auch RANSAC.
Gemessen auf einer 512x512-Fläche mit 4 Kratzern von 3 µm Tiefe, auf einer Seite gehäuft, wobei nur die Breite der Kratzer
variiert wird (eine Neigung von 0.050/-0.025 wird eingeprägt und entfernt; die Ground Truth ist die Fläche selbst inklusive Kratzer):
Kratzer-HWHM Flächenanteil LS-Sq-Fehler RANSAC-Sq-Fehler Gewinn
4 µm 5.6 % -1.94 % -0.39 % 5.0x
12 µm 16.3 % -6.47 % -3.03 % 2.1x
24 µm 31.0 % -13.79 % -11.53 % 1.2x
40 µm 46.0 % -23.80 % -23.56 % 1.0x
3 Dinge lassen sich ablesen:
• Entscheidend ist nicht die Tiefe, sondern der Flächenanteil. "Tiefer Kratzer = robust nötig" ist voreilig; richtig ist "breite Ausreißer = robust nötig".
• Der Fehler fällt immer zu niedrig aus — weil die kleinsten Quadrate sogar "die echte Asymmetrie, die daher rührt, dass die Kratzer auf einer Seite liegen" als Ebene aufsaugen. Bei Gut/Schlecht-Entscheidungen versagt es in die gefährliche Richtung.
• Bei einem Flächenanteil von 46 % hilft auch RANSAC nicht (Gewinn 1.0x). Belegen Ausreißer fast die Hälfte, wählt die Mehrheitsentscheidung von RANSAC selbst die Kratzer. Robustes Anpassen ist ein Werkzeug mit der Prämisse "Ausreißer sind eine Minderheit", und wo diese Prämisse bricht, lässt sich nur mit einer Tabelle zeigen.
★ Falle — legt man λc nachgelagert, verschwindet der Unterschied zwischen LS und RANSAC
Wendet man auf dieselbe Fläche (HWHM 4 µm) nachträglich einen λc=80 µm-Hochpass an,
beträgt der Sq-Fehler LS +0.00 % / RANSAC -0.00 % (in der Tabelle oben ein Unterschied von 5.0x).
Die zusätzlich entfernte Ebene ist reine Langwelligkeit, daher wirft der Hochpass dasselbe nur
noch einmal weg. Die Robustheit der Anpassung zählt bei Abläufen ohne λc (Ebenheit, Formabweichung). Wer nur die Rauheit betrachtet, wird durch die Reihenfolge gerettet.
Die Ebene selbst wird übrigens auch mit LS gut wiederhergestellt: Für die oben eingeprägten Gradienten
0.050 / -0.025 liefert es 0.050006 / -0.025127 (gemessen).
fail-closed
• order nicht 1 oder 2 / method nicht "ls" oder "ransac".
• thresh nicht positiv oder nicht endlich.
• RANSAC kann die vorgeschriebene Anzahl Inlier nicht sammeln (entartete Fläche).
• Leitfaden zur Familie surface_roughness
• 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.
• poc_polish_wipe_measure — py -3.11 examples/poc_polish_wipe_measure.py
• poc_pv_thermal_survey — py -3.11 examples/poc_pv_thermal_survey.py
• poc_surface_roughness — py -3.11 examples/poc_surface_roughness.py
depth als Eingabe)surface_filter · surface_params · surface_psd
prepare)*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.