Doku: Zaehlfunktion und ihre Grenzen auf das neue Verfahren aktualisiert
Beschreibt oertlichen Kontrast statt Otsu (Normierung, Glaettung, oertlicher Hintergrund, Massstab relativ zur groessten Flaeche) und die neuen Grenzen: Untergrund muss sich abheben, gleichmaessige Ausleuchtung hilft, auseinandergelegt zaehlt besser als aufgehaeuft, stark unterschiedlich grosse Teile verfaelschen die Hochrechnung. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -182,21 +182,40 @@ keine Daten verlassen das Gerät.
|
||||
Stapel-Zuweisung; die Zahl wird nirgends gespeichert, nicht einmal
|
||||
flüchtig für die Dauer der Sitzung.
|
||||
|
||||
Kein Bilderkennungsmodell: Der Ausschnitt wird über denselben
|
||||
**Otsu-Schwellwert** wie die Texterkennung in zwei Klassen geteilt
|
||||
(`threshold.js`, aus `ocr.js` herausgezogen, damit beide Funktionen sich
|
||||
dieselbe Schwellwertbestimmung teilen, ohne dass die reine Zählung an
|
||||
`tesseract.js` hinge). Die flächenmäßig **kleinere** der beiden Klassen
|
||||
gilt als Objekt — die ausgelegten Teile belegen so gut wie immer weniger
|
||||
Fläche als der Untergrund, unabhängig davon, ob sie heller oder dunkler
|
||||
sind als dieser; der Nutzer muss nichts einstellen. Anschließend werden
|
||||
zusammenhängende Objektflächen ermittelt (Connected-Component-Labeling
|
||||
mit einer eigenen Arbeitsliste statt Rekursion, damit ein rund eine
|
||||
Million Bildpunkte großer Ausschnitt nicht in den Stapelüberlauf läuft),
|
||||
winzige Flächen als Rauschen verworfen und auffällig große Flächen
|
||||
(mehrere berührende Teile) auf ein Vielfaches der typischen
|
||||
Einzelteilgröße hochgerechnet. Details und Begründung der verwendeten
|
||||
Schwellen: `.superpowers/sdd/counting-report.md`.
|
||||
Kein Bilderkennungsmodell: Der **Otsu-Schwellwert** (`threshold.js`),
|
||||
den die Texterkennung weiterhin nutzt, taugt für „Zählen" nicht — er
|
||||
setzt voraus, dass Objekt- und Untergrundfläche etwa gleich groß sind.
|
||||
Am echten Foto des Auftraggebers (rund zwanzig silberne
|
||||
Festplattenschrauben auf dunklem Leder) belegen die Schrauben unter
|
||||
einem Prozent der Fläche; Otsu rutschte deshalb auf den höchsten
|
||||
Helligkeitswert und erklärte nur die hellsten Punkte der Ledernarbung
|
||||
zum Objekt (gemessenes Fehlverhalten: 76712 statt rund zwanzig). Über
|
||||
die Helligkeit allein sind Schraube und Untergrund an diesem Foto gar
|
||||
nicht trennbar.
|
||||
|
||||
`countObjects` (`src/count-objects.js`) verwendet stattdessen
|
||||
**örtlichen Kontrast**: Der Ausschnitt wird auf 800 Bildpunkte Breite
|
||||
normiert (schmalere Ausschnitte bleiben unverändert — macht alle
|
||||
folgenden Maße unabhängig von der Kameraauflösung), in Graustufen
|
||||
gewandelt und mit einem Kastenfilter geglättet (unterdrückt feine
|
||||
Untergrundnarbung, über ein Summenbild für radius-unabhängige
|
||||
Laufzeit). Ein zweiter, deutlich größerer Kastenmittelwert liefert den
|
||||
**örtlichen Hintergrund** an jeder Stelle — das fängt ungleichmäßige
|
||||
Ausleuchtung ab. Ein Bildpunkt gilt als Objekt, wenn er um mehr als
|
||||
einen festen Betrag heller **oder** dunkler ist als sein örtlicher
|
||||
Hintergrund (beide Richtungen werden berechnet; es gewinnt die mit den
|
||||
meisten gefundenen Einzelflächen — Details siehe unten). Anschließend
|
||||
werden zusammenhängende Objektflächen ermittelt
|
||||
(Connected-Component-Labeling mit einer eigenen Arbeitsliste statt
|
||||
Rekursion, damit ein rund eine Viertelmillion Bildpunkte großer
|
||||
Ausschnitt nicht in den Stapelüberlauf läuft), winzige Flächen als
|
||||
Rauschen verworfen und nur Flächen ab einem festen **Anteil der
|
||||
größten gefundenen Fläche** behalten — bewusst relativ, nicht absolut,
|
||||
damit ein näher oder weiter weg gehaltenes Kamerabild die Zählung nicht
|
||||
verstellt. Auffällig große Flächen (mehrere berührende Teile) werden
|
||||
auf ein Vielfaches der typischen (Median-)Einzelteilgröße
|
||||
hochgerechnet. Details, alle verwendeten Schwellen und die Messung am
|
||||
echten Foto: `.superpowers/sdd/counting-rework-report.md`.
|
||||
5. **Stapel-Zuweisung.** Grün (Barcode) und Gelb (OCR) laufen ohne Eingabe
|
||||
durch; nur bei roter Konfidenz (nichts Eindeutiges erkannt, widersprüchliche
|
||||
Barcodes oder widersprüchliche unbekannte Barcodes ohne jede OCR-Kapazität)
|
||||
@@ -334,7 +353,7 @@ worauf du bei der Veröffentlichung achten solltest.
|
||||
| `src/scan-modes.js` | Die vier Scan-Funktionen (Strichcode, QR-Code, Text erkennen, Zählen): Kennung, deutsche Beschriftung, gelesene Codearten, laufende Suche ja/nein, Texterkennung ja/nein, laufende Zählung ja/nein — einzige Quelle, sowohl für die Auswahl-Oberfläche als auch für `main.js` |
|
||||
| `src/scan-recognition.js` | Baut die an `recognize()` übergebenen Adapter anhand der gewählten Funktion: in „Strichcode"/„QR-Code" liefert die Texterkennung sofort leeren Text ohne Tesseract anzustoßen, in „Text erkennen" liefert die Barcode-Dekodierung sofort eine leere Liste ohne `zxing-wasm` anzustoßen, in „Zählen" liefern beide sofort leer (diese Funktion ruft `recognize()` im normalen Betrieb ohnehin nicht auf) |
|
||||
| `src/threshold.js` | Otsu-Schwellwertbestimmung (Graustufen, Histogramm, Schwellwert) — reines Modul ohne Browser-Zugriff, aus `ocr.js` herausgezogen; gemeinsame Grundlage für `preprocess()` (ocr.js) und `countObjects()` (count-objects.js) |
|
||||
| `src/count-objects.js` | Reine Berechnung für Funktion „Zählen": zählt zusammenhängende Objektflächen in einem Bildausschnitt (Otsu-Schwellwert aus `threshold.js`, flächenmäßig kleinere Klasse gilt als Objekt, Connected-Component-Labeling mit eigener Arbeitsliste, Rauschfilter, Hochrechnung berührender Teile über den Flächen-Median) |
|
||||
| `src/count-objects.js` | Reine Berechnung für Funktion „Zählen": zählt zusammenhängende Objektflächen in einem Bildausschnitt über örtlichen Kontrast (Normierung auf 800 Bildpunkte Breite, Glättung und örtlicher Hintergrund je über Kastenfilter/Summenbild, Maske aus geglättetem Bild vs. örtlichem Hintergrund ± Marge, beide Polaritäten, Connected-Component-Labeling mit eigener Arbeitsliste, Rauschfilter, Massstab relativ zur größten Fläche, Hochrechnung berührender Teile über den Flächen-Median) — nutzt `threshold.js`/Otsu bewusst **nicht** mehr (siehe „Funktionsweise" oben) |
|
||||
| `src/storage.js` | Absturzschutz der laufenden Sitzung: sichert und lädt aus `localStorage`, verwirft beim Laden jeden in sich unstimmigen Zustand vollständig (siehe unten); `entry.rawText` ist wie `entry.codes` optional und wird bei Fehlen als leerer Rohtext wiederhergestellt |
|
||||
| `src/camera.js` | Kamerastart, Einzelbildaufnahme (herunterskaliert, für die Dateiauswahl), Rahmenausschnitt in voller Auflösung (`grabFrameRegion`, für die laufende Barcode-Suche, „Modul scannen" in „Text erkennen" **und** die laufende Zählung in „Zählen"), Bilddatei-Ersatzweg |
|
||||
| `src/barcode.js` | Adapter zu `zxing-wasm`; `decodeBarcodes(imageData, formats)` bekommt die Codearten übergeben, ohne Angabe wie bisher (Code128 + DataMatrix) |
|
||||
@@ -433,35 +452,41 @@ Eintrag und fließt in keine Stapel-Berechnung ein.
|
||||
Modul einen eigenen Stapel erzeugen.
|
||||
- **Funktion „Zählen" ist eine Schätzung, keine exakte Zählung** — sie wird
|
||||
ungenau, wenn eine der folgenden Bedingungen zutrifft:
|
||||
- **Berührende oder gestapelte Teile.** Mehrere Teile, die sich berühren,
|
||||
bilden eine einzige zusammenhängende Fläche. Die App rechnet diese über
|
||||
die typische Einzelteilgröße (Median der gefundenen Flächen) auf ein
|
||||
Vielfaches hoch, aber je unregelmäßiger sich die Teile überlappen
|
||||
(z. B. drei Schrauben, die sich gegenseitig teilweise verdecken statt
|
||||
sich nur zu berühren), desto ungenauer wird die hochgerechnete Fläche.
|
||||
Liegen Teile übereinander gestapelt statt nebeneinander ausgelegt, sieht
|
||||
die Kamera von oben nur die Fläche des obersten Teils — verdeckte Teile
|
||||
werden nicht mitgezählt.
|
||||
- **Ungleichmäßige Ausleuchtung.** Der Otsu-Schwellwert ist ein einziger,
|
||||
fester Wert für den gesamten Ausschnitt. Fällt Licht sehr einseitig ein
|
||||
(z. B. ein Teil des Rahmens hell, der Rest im Schatten), kann derselbe
|
||||
Untergrund an einer Stelle über und an einer anderen Stelle unter dem
|
||||
Schwellwert liegen — Teile im schlechter ausgeleuchteten Bereich werden
|
||||
dann leicht übersehen oder der Untergrund selbst fälschlich als
|
||||
Objektfläche gewertet.
|
||||
- **Zu geringer Kontrast zum Untergrund.** Je ähnlicher sich Objekt- und
|
||||
Untergrundhelligkeit sind, desto unschärfer die Trennung durch Otsu —
|
||||
bei sehr geringem Kontrast können Teile am Rand verloren gehen oder mit
|
||||
dem Untergrund verschmelzen.
|
||||
- **Stark unterschiedlich große Teile.** Die Hochrechnung setzt voraus,
|
||||
dass die meisten Fundstücke ungefähr gleich groß sind (der Median dient
|
||||
als Maßstab für „ein Teil"). Liegen im selben Rahmen sowohl deutlich
|
||||
größere als auch deutlich kleinere Teile derselben Sorte (oder gar
|
||||
unterschiedliche Teile gemischt), kann die Rauschschwelle ein
|
||||
tatsächliches kleines Teil verwerfen oder die Hochrechnung ein einzelnes
|
||||
großes Teil als mehrere zählen.
|
||||
- Details, die verwendeten Schwellenwerte und ihre Begründung stehen in
|
||||
`.superpowers/sdd/counting-report.md`.
|
||||
- **Der Untergrund muss sich abheben.** Das Verfahren erkennt Fundstücke
|
||||
über den örtlichen Kontrast zu ihrer unmittelbaren Umgebung (siehe
|
||||
„Funktionsweise" oben) — es braucht also eine Stelle, an der sich das
|
||||
Fundstück *lokal* von dem unterscheidet, was um es herum liegt. Ein
|
||||
Fundstück, das nahezu dieselbe Helligkeit wie der Tisch/das Leder
|
||||
darunter hat, wird nicht zuverlässig gefunden.
|
||||
- **Gleichmäßige Ausleuchtung hilft.** Der örtliche Hintergrund wird aus
|
||||
einem Fenster um jeden Bildpunkt gebildet und fängt einseitigen
|
||||
Lichteinfall dadurch besser ab als ein einzelner, fester Schwellwert
|
||||
für das ganze Bild. Sehr harte Schlagschatten oder Reflexe können
|
||||
trotzdem eigene, dem Fundstück ähnliche Kontrastflächen erzeugen (siehe
|
||||
„mehrere gefundene Flächen" unten) und die Zählung verfälschen.
|
||||
- **Auseinandergelegt zählt besser als aufgehäuft/berührend.** Mehrere
|
||||
Teile, die sich berühren, bilden eine einzige zusammenhängende Fläche.
|
||||
Die App rechnet diese über die typische Einzelteilgröße (Median der
|
||||
gefundenen Flächen) auf ein Vielfaches hoch, aber je unregelmäßiger sich
|
||||
die Teile überlappen (z. B. mehrere Schrauben, die sich gegenseitig
|
||||
teilweise verdecken statt sich nur zu berühren), desto ungenauer wird
|
||||
die hochgerechnete Fläche — und je dichter die Teile gedrängt liegen,
|
||||
desto eher sieht das Umgebungsfenster (siehe oben) an ihrer eigenen
|
||||
Stelle vor allem Nachbarteile statt echten Untergrund. Liegen Teile
|
||||
übereinander gestapelt statt nebeneinander ausgelegt, sieht die Kamera
|
||||
von oben nur die Fläche des obersten Teils — verdeckte Teile werden
|
||||
nicht mitgezählt.
|
||||
- **Stark unterschiedlich große Teile verfälschen die Hochrechnung.** Die
|
||||
Hochrechnung setzt voraus, dass die meisten Fundstücke ungefähr gleich
|
||||
groß sind (der Median dient als Maßstab für „ein Teil"). Liegen im
|
||||
selben Rahmen sowohl deutlich größere als auch deutlich kleinere Teile
|
||||
derselben Sorte (oder gar unterschiedliche Teile gemischt), kann die
|
||||
Rauschschwelle ein tatsächliches kleines Teil verwerfen oder die
|
||||
Hochrechnung ein einzelnes großes Teil als mehrere zählen.
|
||||
- Details, die verwendeten Schwellenwerte, ihre Begründung und die
|
||||
Messung am echten Foto (~20 Festplattenschrauben auf Leder, für das
|
||||
das alte Otsu-basierte Verfahren 76712 statt rund zwanzig meldete)
|
||||
stehen in `.superpowers/sdd/counting-rework-report.md`.
|
||||
|
||||
## Herstellertabellen erweitern
|
||||
|
||||
|
||||
Reference in New Issue
Block a user