Doku: vierte Funktion "Zählen" im README ergänzt
Funktionstabelle, Ablaufbeschreibung, Aufbau-Tabelle (threshold.js, count-objects.js), Testzahl (165), neuer Grenzen-Abschnitt (beruehrende/ gestapelte Teile, ungleichmaessige Ausleuchtung, geringer Kontrast, stark unterschiedliche Teilegroessen) sowie ein Geraete-Pruefpunkt fuer "Zählen". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,10 +4,13 @@ Browser-App, die per Handykamera gebrauchte Server-RAM-Module erkennt und
|
|||||||
beim physischen Sortieren am Tisch anleitet: Modul vor die Kamera halten, die
|
beim physischen Sortieren am Tisch anleitet: Modul vor die Kamera halten, die
|
||||||
App nennt den Stapel.
|
App nennt den Stapel.
|
||||||
|
|
||||||
Vor dem Scannen wählt der Nutzer eine von drei Funktionen — Strichcode,
|
Vor dem Scannen wählt der Nutzer eine von vier Funktionen — Strichcode,
|
||||||
QR-Code oder Text erkennen (siehe „Funktionsweise" unten). Jede Funktion nutzt
|
QR-Code, Text erkennen oder Zählen (siehe „Funktionsweise" unten). Jede
|
||||||
ausschließlich ihre eigene Quelle; anders als früher weicht die App nicht mehr
|
Funktion nutzt ausschließlich ihre eigene Quelle; anders als früher weicht die
|
||||||
automatisch auf Texterkennung aus, wenn kein Code gefunden wird.
|
App nicht mehr automatisch auf Texterkennung aus, wenn kein Code gefunden
|
||||||
|
wird. Die vierte Funktion, „Zählen", gehört nicht zum eigentlichen Sortieren:
|
||||||
|
Sie bucht nichts, sondern zeigt beim Auslegen von Kleinteilen (z. B.
|
||||||
|
Festplattenschrauben) fortlaufend deren Anzahl an.
|
||||||
|
|
||||||
Zwei Module gelten als zusammengehörig, wenn sie denselben Barcode-Inhalt
|
Zwei Module gelten als zusammengehörig, wenn sie denselben Barcode-Inhalt
|
||||||
tragen — ein Barcode ist exakt gelesen, das ist der zuverlässigste Maßstab.
|
tragen — ein Barcode ist exakt gelesen, das ist der zuverlässigste Maßstab.
|
||||||
@@ -57,16 +60,17 @@ keine Daten verlassen das Gerät.
|
|||||||
## Funktionsweise
|
## Funktionsweise
|
||||||
|
|
||||||
0. **Funktion wählen.** Vor dem ersten Scan (und jederzeit erneut über die
|
0. **Funktion wählen.** Vor dem ersten Scan (und jederzeit erneut über die
|
||||||
antippbare Anzeige in der Scan-Ansicht) wählt der Nutzer eine von drei
|
antippbare Anzeige in der Scan-Ansicht) wählt der Nutzer eine von vier
|
||||||
Funktionen. Kennung, Beschriftung, gelesene Codearten und Verhalten stehen
|
Funktionen. Kennung, Beschriftung, gelesene Codearten und Verhalten stehen
|
||||||
ausschließlich in `src/scan-modes.js` — es gibt keine zweite Stelle, an der
|
ausschließlich in `src/scan-modes.js` — es gibt keine zweite Stelle, an der
|
||||||
das steht:
|
das steht:
|
||||||
|
|
||||||
| Funktion | Liest | Laufende Suche | Texterkennung |
|
| Funktion | Liest | Laufende Suche/Zählung | Texterkennung |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| **Strichcode** | Code128, Code39, Code93, ITF, EAN-13, EAN-8, UPC-A, UPC-E, Codabar | ja | nein |
|
| **Strichcode** | Code128, Code39, Code93, ITF, EAN-13, EAN-8, UPC-A, UPC-E, Codabar | ja (Codesuche) | nein |
|
||||||
| **QR-Code** | QRCode, MicroQRCode, RMQRCode, DataMatrix, Aztec, PDF417 | ja | nein |
|
| **QR-Code** | QRCode, MicroQRCode, RMQRCode, DataMatrix, Aztec, PDF417 | ja (Codesuche) | nein |
|
||||||
| **Text erkennen** | keine Codes | nein | ja, auf Knopfdruck |
|
| **Text erkennen** | keine Codes | nein | ja, auf Knopfdruck |
|
||||||
|
| **Zählen** | keine Codes | ja (Zählung, keine Buchung) | nein |
|
||||||
|
|
||||||
„QR-Code" heißt auf Wunsch des Auftraggebers „QR-Code", liest aber bewusst
|
„QR-Code" heißt auf Wunsch des Auftraggebers „QR-Code", liest aber bewusst
|
||||||
nicht nur QR-Varianten, sondern auch DataMatrix, Aztec und PDF417. Der
|
nicht nur QR-Varianten, sondern auch DataMatrix, Aztec und PDF417. Der
|
||||||
@@ -90,17 +94,21 @@ keine Daten verlassen das Gerät.
|
|||||||
verschwindet.
|
verschwindet.
|
||||||
|
|
||||||
Liegt beim Start eine gesicherte Sitzung vor, erscheint zuerst die Frage
|
Liegt beim Start eine gesicherte Sitzung vor, erscheint zuerst die Frage
|
||||||
nach dem Fortsetzen (siehe Punkt 5 unten) und erst danach die Funktionswahl
|
nach dem Fortsetzen (siehe Punkt 6 unten) und erst danach die Funktionswahl
|
||||||
— die Kamera startet in jedem Fall erst, nachdem beides geklärt ist.
|
— die Kamera startet in jedem Fall erst, nachdem beides geklärt ist.
|
||||||
|
|
||||||
Technisch bekommen „Strichcode" und „QR-Code" eine Texterkennung
|
Technisch bekommen „Strichcode" und „QR-Code" eine Texterkennung
|
||||||
hineingereicht, die sofort leeren Text liefert, ohne Tesseract anzustoßen;
|
hineingereicht, die sofort leeren Text liefert, ohne Tesseract anzustoßen;
|
||||||
„Text erkennen" bekommt eine Barcode-Dekodierung hineingereicht, die sofort
|
„Text erkennen" bekommt eine Barcode-Dekodierung hineingereicht, die sofort
|
||||||
eine leere Liste liefert (`buildRecognitionAdapters` in
|
eine leere Liste liefert; „Zählen" bekommt beides leer hineingereicht
|
||||||
`src/scan-recognition.js`). Die Erkennungs-Pipeline selbst (`src/pipeline.js`,
|
(`buildRecognitionAdapters` in `src/scan-recognition.js`). Die
|
||||||
Punkte 1–4 unten) bleibt dabei unverändert und kennt keine Funktionen — die
|
Erkennungs-Pipeline selbst (`src/pipeline.js`, Punkte 1–3 und 5 unten)
|
||||||
drei Funktionen unterscheiden sich ausschließlich darin, welche Adapter ihr
|
bleibt dabei unverändert und kennt keine Funktionen — die drei
|
||||||
übergeben werden.
|
code-/textbasierten Funktionen unterscheiden sich ausschließlich darin,
|
||||||
|
welche Adapter ihr übergeben werden. „Zählen" ruft diese Pipeline im
|
||||||
|
normalen Betrieb gar nicht erst auf (siehe Punkt 4 unten) — es gibt dort ja
|
||||||
|
nichts zu buchen, das leere Adapterpaar dient nur als Absicherung für den
|
||||||
|
seltenen Ersatzweg ohne Kamera (Punkt 7).
|
||||||
1. **Barcode-Dekodierung** (nur in „Strichcode" und „QR-Code"). Die zur
|
1. **Barcode-Dekodierung** (nur in „Strichcode" und „QR-Code"). Die zur
|
||||||
Funktion gehörenden Codearten werden laufend aus dem Kamerabild dekodiert
|
Funktion gehörenden Codearten werden laufend aus dem Kamerabild dekodiert
|
||||||
(`zxing-wasm`, `decodeBarcodes` in `src/barcode.js` bekommt die Codearten
|
(`zxing-wasm`, `decodeBarcodes` in `src/barcode.js` bekommt die Codearten
|
||||||
@@ -163,18 +171,44 @@ keine Daten verlassen das Gerät.
|
|||||||
auszublenden wie in den beiden Barcode-Funktionen (`showResult` in
|
auszublenden wie in den beiden Barcode-Funktionen (`showResult` in
|
||||||
`src/ui/result-overlay.js`). Der Rohtext jedes Eintrags lässt sich später
|
`src/ui/result-overlay.js`). Der Rohtext jedes Eintrags lässt sich später
|
||||||
auch in der Sitzungsliste nachlesen.
|
auch in der Sitzungsliste nachlesen.
|
||||||
4. **Stapel-Zuweisung.** Grün (Barcode) und Gelb (OCR) laufen ohne Eingabe
|
4. **Zählen** (ausschließlich in Funktion „Zählen"). Reine Anzeige, ohne
|
||||||
|
jeden Bezug zur Sitzung: Solange die Kamera läuft, wird der Zielrahmen
|
||||||
|
mehrmals pro Sekunde ausgewertet und die Anzahl der darin gefundenen
|
||||||
|
Fundstücke groß im Bild eingeblendet (`countObjects` in
|
||||||
|
`src/count-objects.js`, aufgerufen über denselben Zeitgeber/dieselbe
|
||||||
|
Überlappungssperre wie die Barcode-Dauersuche — siehe
|
||||||
|
`continuousSearchLoop` in `src/main.js`). Es gibt in dieser Funktion
|
||||||
|
keinen „Modul scannen"-Knopf, keine Treffer-Rückmeldung und keine
|
||||||
|
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`.
|
||||||
|
5. **Stapel-Zuweisung.** Grün (Barcode) und Gelb (OCR) laufen ohne Eingabe
|
||||||
durch; nur bei roter Konfidenz (nichts Eindeutiges erkannt, widersprüchliche
|
durch; nur bei roter Konfidenz (nichts Eindeutiges erkannt, widersprüchliche
|
||||||
Barcodes oder widersprüchliche unbekannte Barcodes ohne jede OCR-Kapazität)
|
Barcodes oder widersprüchliche unbekannte Barcodes ohne jede OCR-Kapazität)
|
||||||
oder mehrdeutiger Stapelzuordnung fragt die App nach.
|
oder mehrdeutiger Stapelzuordnung fragt die App nach.
|
||||||
5. **Sitzungsfortsetzung beim Start.** Findet die App beim Laden eine in
|
6. **Sitzungsfortsetzung beim Start.** Findet die App beim Laden eine in
|
||||||
`localStorage` gesicherte, nicht leere Sitzung vor, wird sie nicht
|
`localStorage` gesicherte, nicht leere Sitzung vor, wird sie nicht
|
||||||
stillschweigend übernommen, sondern zur Fortsetzung oder zum Verwerfen
|
stillschweigend übernommen, sondern zur Fortsetzung oder zum Verwerfen
|
||||||
angeboten (`askResumeSession` in `src/ui/resume-dialog.js`, verdrahtet über
|
angeboten (`askResumeSession` in `src/ui/resume-dialog.js`, verdrahtet über
|
||||||
`initResumeOffer()` in `src/main.js`). Erst „fortsetzen“ stellt Stapel,
|
`initResumeOffer()` in `src/main.js`). Erst „fortsetzen“ stellt Stapel,
|
||||||
Zähler und die „Zuletzt“-Zeile wieder her; „verwerfen“ löscht den
|
Zähler und die „Zuletzt“-Zeile wieder her; „verwerfen“ löscht den
|
||||||
gesicherten Stand und die App startet leer.
|
gesicherten Stand und die App startet leer.
|
||||||
6. **Ersatzweg ohne Kamera.** Lässt sich die Kamera nicht starten (z. B.
|
7. **Ersatzweg ohne Kamera.** Lässt sich die Kamera nicht starten (z. B.
|
||||||
verweigerte Berechtigung), bleibt die App bedienbar: eine dauerhaft
|
verweigerte Berechtigung), bleibt die App bedienbar: eine dauerhaft
|
||||||
sichtbare Schaltfläche „Bild auswählen“ öffnet stattdessen die native
|
sichtbare Schaltfläche „Bild auswählen“ öffnet stattdessen die native
|
||||||
Dateiauswahl (`setFilePickerVisible` in `src/ui/scan-view.js`). Die App
|
Dateiauswahl (`setFilePickerVisible` in `src/ui/scan-view.js`). Die App
|
||||||
@@ -213,22 +247,26 @@ korrekt funktioniert.
|
|||||||
npm test
|
npm test
|
||||||
```
|
```
|
||||||
|
|
||||||
154 Tests, alle grün (Stand dieses Dokuments). Getestet werden ausschließlich
|
165 Tests, alle grün (Stand dieses Dokuments). Getestet werden ausschließlich
|
||||||
die reinen Module ohne Browser-Zugriff: Teilenummer-Decoder, Spec-Normalisierung
|
die reinen Module ohne Browser-Zugriff: Teilenummer-Decoder, Spec-Normalisierung
|
||||||
und toleranter Vergleich, OCR-Bildaufbereitung (Otsu-Schwellwert) und
|
und toleranter Vergleich, OCR-Bildaufbereitung (Otsu-Schwellwert, jetzt in
|
||||||
-Feldextraktion, Stapel-Zuweisung, die Erkennungs-Pipeline samt Zeitgrenzen,
|
`threshold.js`) und -Feldextraktion, Stapel-Zuweisung, die Erkennungs-Pipeline
|
||||||
Mehrdeutigkeitsbehandlung und dem additiven OCR-Rohtext (`rawText` wird nur
|
samt Zeitgrenzen, Mehrdeutigkeitsbehandlung und dem additiven OCR-Rohtext
|
||||||
zurückgegeben, wenn die Texterkennung tatsächlich lief, und beeinflusst
|
(`rawText` wird nur zurückgegeben, wenn die Texterkennung tatsächlich lief,
|
||||||
nachweislich nie die Stapelzuordnung), die Sitzungssicherung samt Prüfung
|
und beeinflusst nachweislich nie die Stapelzuordnung), die Sitzungssicherung
|
||||||
eines wiederhergestellten Zustands (einschließlich `entry.rawText`), die drei
|
samt Prüfung eines wiederhergestellten Zustands (einschließlich
|
||||||
Scan-Funktionen (`scan-modes.js` —
|
`entry.rawText`), die vier Scan-Funktionen (`scan-modes.js` — Codearten je
|
||||||
Codearten je Funktion, DataMatrix/Aztec/PDF417 in „QR-Code") sowie die je Funktion
|
Funktion, DataMatrix/Aztec/PDF417 in „QR-Code") sowie die je Funktion
|
||||||
tatsächlich aufgerufenen Adapter (`scan-recognition.js` — Texterkennung läuft
|
tatsächlich aufgerufenen Adapter (`scan-recognition.js` — Texterkennung läuft
|
||||||
nachweislich nie in „Strichcode"/„QR-Code", Barcode-Dekodierung nachweislich
|
nachweislich nie in „Strichcode"/„QR-Code", Barcode-Dekodierung nachweislich
|
||||||
nie in „Text erkennen"). Kamera, Barcode-/OCR-Adapter selbst, die
|
nie in „Text erkennen"/„Zählen"). Dazu die Zähl-Berechnung selbst
|
||||||
Auswahl-Oberfläche und die Verdrahtung in `main.js` laufen nur im echten
|
(`count-objects.js` — leeres Bild, einzelne und mehrere getrennte Flächen,
|
||||||
Browser und werden dort manuell geprüft (siehe „Am Gerät noch zu prüfen"
|
verworfenes Rauschen, Hochrechnung berührender Teile ohne ein nur leicht
|
||||||
unten) — `node --test` kennt kein DOM.
|
größeres Einzelteil zu verdoppeln, helle wie dunkle Objekte, ein Bild ohne
|
||||||
|
Bildpunkte). Kamera, Barcode-/OCR-Adapter selbst, die Auswahl-Oberfläche und
|
||||||
|
die Verdrahtung in `main.js` laufen nur im echten Browser und werden dort
|
||||||
|
manuell geprüft (siehe „Am Gerät noch zu prüfen" unten) — `node --test` kennt
|
||||||
|
kein DOM.
|
||||||
|
|
||||||
## Produktion
|
## Produktion
|
||||||
|
|
||||||
@@ -293,14 +331,16 @@ worauf du bei der Veröffentlichung achten solltest.
|
|||||||
| `src/ocr-extract.js` | OCR-Rohtext → Spec-Felder |
|
| `src/ocr-extract.js` | OCR-Rohtext → Spec-Felder |
|
||||||
| `src/session.js` | Stapel halten, vorschlagen, buchen, umsortieren, zurücknehmen — inklusive der aus den Einträgen abgeleiteten, je Stapel bekannten Barcode-Inhalte (`stack.codes`), die vor dem Vergleich der technischen Angaben über die Zuordnung entscheiden, sofern diese Angaben nicht widersprechen |
|
| `src/session.js` | Stapel halten, vorschlagen, buchen, umsortieren, zurücknehmen — inklusive der aus den Einträgen abgeleiteten, je Stapel bekannten Barcode-Inhalte (`stack.codes`), die vor dem Vergleich der technischen Angaben über die Zuordnung entscheiden, sofern diese Angaben nicht widersprechen |
|
||||||
| `src/pipeline.js` | Barcode → Teilenummer → OCR → Ampelfarbe, inkl. Zeitgrenzen, Mehrdeutigkeitsbehandlung und Kurzschluss über einen bereits bekannten Barcode-Inhalt (`deps.isKnownCode`) — kennt keine Scan-Funktionen; liefert zusätzlich (additiv) den ungefilterten OCR-Rohtext (`rawText`), leer, wenn keine Texterkennung lief |
|
| `src/pipeline.js` | Barcode → Teilenummer → OCR → Ampelfarbe, inkl. Zeitgrenzen, Mehrdeutigkeitsbehandlung und Kurzschluss über einen bereits bekannten Barcode-Inhalt (`deps.isKnownCode`) — kennt keine Scan-Funktionen; liefert zusätzlich (additiv) den ungefilterten OCR-Rohtext (`rawText`), leer, wenn keine Texterkennung lief |
|
||||||
| `src/scan-modes.js` | Die drei Scan-Funktionen (Strichcode, QR-Code, Text erkennen): Kennung, deutsche Beschriftung, gelesene Codearten, laufende Suche ja/nein, Texterkennung ja/nein — einzige Quelle, sowohl für die Auswahl-Oberfläche als auch für `main.js` |
|
| `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 |
|
| `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/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/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 **und** für „Modul scannen" in „Text erkennen"), Bilddatei-Ersatzweg |
|
| `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) |
|
| `src/barcode.js` | Adapter zu `zxing-wasm`; `decodeBarcodes(imageData, formats)` bekommt die Codearten übergeben, ohne Angabe wie bisher (Code128 + DataMatrix) |
|
||||||
| `src/ocr.js` | Bildaufbereitung (Otsu) und Adapter zu `tesseract.js`; Zeichen-Whitelist deckt Groß- und Kleinbuchstaben, Ziffern sowie übliche Etiketten-Sonderzeichen ab |
|
| `src/ocr.js` | Bildaufbereitung (Otsu, über `threshold.js`) und Adapter zu `tesseract.js`; Zeichen-Whitelist deckt Groß- und Kleinbuchstaben, Ziffern sowie übliche Etiketten-Sonderzeichen ab |
|
||||||
| `src/ui/scan-view.js` | Scan-Ansicht: Kamera-Vorschau, antippbare Anzeige der gewählten Funktion (Wechsel), Scan-Knopf (nur in „Text erkennen" sichtbar), Stapel-Leiste, „Zuletzt"-Zeile, Ersatzweg-Schaltfläche bei fehlender Kamera |
|
| `src/ui/scan-view.js` | Scan-Ansicht: Kamera-Vorschau, antippbare Anzeige der gewählten Funktion (Wechsel), Scan-Knopf (nur in „Text erkennen" sichtbar), große Zählanzeige (nur in „Zählen" sichtbar), Stapel-Leiste, „Zuletzt"-Zeile, Ersatzweg-Schaltfläche bei fehlender Kamera |
|
||||||
| `src/ui/mode-dialog.js` | Vollbild-Auswahl der Scan-Funktion vor dem Start und beim Wechsel: drei große Flächen, eine je Funktion aus `src/scan-modes.js` |
|
| `src/ui/mode-dialog.js` | Vollbild-Auswahl der Scan-Funktion vor dem Start und beim Wechsel: vier große Flächen, eine je Funktion aus `src/scan-modes.js` |
|
||||||
| `src/ui/result-overlay.js` | Treffer-Rückmeldung (grün/gelb): blendet sich in „Strichcode"/„QR-Code" nach kurzer Zeit selbst aus; in „Text erkennen" bleibt sie stehen, zeigt den vollen OCR-Rohtext und wartet auf eine Eingabe, bevor sie schließt |
|
| `src/ui/result-overlay.js` | Treffer-Rückmeldung (grün/gelb): blendet sich in „Strichcode"/„QR-Code" nach kurzer Zeit selbst aus; in „Text erkennen" bleibt sie stehen, zeigt den vollen OCR-Rohtext und wartet auf eine Eingabe, bevor sie schließt |
|
||||||
| `src/ui/ambiguous-dialog.js` | Rot-Dialog bei roter Konfidenz oder mehrdeutiger Stapelzuordnung |
|
| `src/ui/ambiguous-dialog.js` | Rot-Dialog bei roter Konfidenz oder mehrdeutiger Stapelzuordnung |
|
||||||
| `src/ui/resume-dialog.js` | Dialog beim Start: gesicherte Sitzung fortsetzen oder verwerfen — läuft vor der Funktionswahl |
|
| `src/ui/resume-dialog.js` | Dialog beim Start: gesicherte Sitzung fortsetzen oder verwerfen — läuft vor der Funktionswahl |
|
||||||
@@ -312,10 +352,11 @@ worauf du bei der Veröffentlichung achten solltest.
|
|||||||
| `.vch/deploy.yaml` | Bau- und Startbefehl sowie Gesundheitspfad für die Hosting-Umgebung |
|
| `.vch/deploy.yaml` | Bau- und Startbefehl sowie Gesundheitspfad für die Hosting-Umgebung |
|
||||||
|
|
||||||
`spec`, `pn-decoder`, `ocr-extract`, `session`, `pipeline`, `storage`,
|
`spec`, `pn-decoder`, `ocr-extract`, `session`, `pipeline`, `storage`,
|
||||||
`scan-modes` und `scan-recognition` sind reine Funktionen ohne Browser-Zugriff
|
`scan-modes`, `scan-recognition`, `threshold` und `count-objects` sind reine
|
||||||
(kein `window`, `document` oder `localStorage` direkt) und deshalb vollständig
|
Funktionen ohne Browser-Zugriff (kein `window`, `document` oder
|
||||||
mit `node:test` prüfbar. `camera.js`, `barcode.js`, `ocr.js` und `src/ui/`
|
`localStorage` direkt) und deshalb vollständig mit `node:test` prüfbar.
|
||||||
brauchen einen echten Browser und werden nur manuell geprüft.
|
`camera.js`, `barcode.js`, `ocr.js` und `src/ui/` brauchen einen echten
|
||||||
|
Browser und werden nur manuell geprüft.
|
||||||
|
|
||||||
### Sitzungssicherung im Detail
|
### Sitzungssicherung im Detail
|
||||||
|
|
||||||
@@ -390,6 +431,37 @@ Eintrag und fließt in keine Stapel-Berechnung ein.
|
|||||||
Aufnahmen (Zeilenumbrüche, zusätzlich erkannte Wörter, Groß-/
|
Aufnahmen (Zeilenumbrüche, zusätzlich erkannte Wörter, Groß-/
|
||||||
Kleinschreibung, …) und würde als Gruppierungsmerkmal für praktisch jedes
|
Kleinschreibung, …) und würde als Gruppierungsmerkmal für praktisch jedes
|
||||||
Modul einen eigenen Stapel erzeugen.
|
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`.
|
||||||
|
|
||||||
## Herstellertabellen erweitern
|
## Herstellertabellen erweitern
|
||||||
|
|
||||||
@@ -433,10 +505,11 @@ werden:
|
|||||||
- Datei-Auswahl als Ersatzweg (ohne Kamera) öffnet den nativen Dialog und
|
- Datei-Auswahl als Ersatzweg (ohne Kamera) öffnet den nativen Dialog und
|
||||||
hinterlässt keine leere Fläche im Layout.
|
hinterlässt keine leere Fläche im Layout.
|
||||||
|
|
||||||
**Funktionswahl (neu)**
|
**Funktionswahl**
|
||||||
- Erster Start ohne gesicherte Sitzung: Auswahl mit drei großen Flächen
|
- Erster Start ohne gesicherte Sitzung: Auswahl mit vier großen Flächen
|
||||||
(„Strichcode", „QR-Code", „Text erkennen") erscheint, *bevor* die Kamera
|
(„Strichcode", „QR-Code", „Text erkennen", „Zählen") erscheint, *bevor* die
|
||||||
startet — kein Kamerabild sichtbar, solange keine Funktion gewählt ist.
|
Kamera startet — kein Kamerabild sichtbar, solange keine Funktion gewählt
|
||||||
|
ist.
|
||||||
- Erster Start *mit* gesicherter Sitzung: erst die Frage „Gesicherte Sitzung
|
- Erster Start *mit* gesicherter Sitzung: erst die Frage „Gesicherte Sitzung
|
||||||
gefunden" (fortsetzen/verwerfen), erst danach die Funktionswahl.
|
gefunden" (fortsetzen/verwerfen), erst danach die Funktionswahl.
|
||||||
- „Strichcode" wählen: laufende Suche erkennt Code-128/Code-39/EAN/UPC/…,
|
- „Strichcode" wählen: laufende Suche erkennt Code-128/Code-39/EAN/UPC/…,
|
||||||
@@ -488,6 +561,23 @@ werden:
|
|||||||
dass die Vorbereitung tatsächlich nur einmal läuft)? In Funktion „Text
|
dass die Vorbereitung tatsächlich nur einmal läuft)? In Funktion „Text
|
||||||
erkennen" darf dieses Laden dagegen gar nicht erst anlaufen, da dort nie
|
erkennen" darf dieses Laden dagegen gar nicht erst anlaufen, da dort nie
|
||||||
`decodeBarcodes` aufgerufen wird.
|
`decodeBarcodes` aufgerufen wird.
|
||||||
|
**Zählen (neu)**
|
||||||
|
- „Zählen" wählen, Kamera auf ausgelegte Kleinteile richten (z. B. silberne
|
||||||
|
Festplattenschrauben auf dunklem Untergrund): Eine große Zahl erscheint im
|
||||||
|
Bild und aktualisiert sich laufend, ohne dass etwas angetippt werden muss.
|
||||||
|
Kein „Modul scannen"-Knopf, keine Treffer-Rückmeldung, kein roter Dialog,
|
||||||
|
keine Stapel-Zuweisung — der Zielrahmen bleibt sichtbar und zeigt weiterhin,
|
||||||
|
was gezählt wird.
|
||||||
|
- Die angezeigte Zahl aus normalem Bedienabstand (Armlänge) lesbar prüfen.
|
||||||
|
- Ein paar Teile wegnehmen bzw. hinzufügen, während die Kamera läuft: Die
|
||||||
|
Zahl folgt ohne spürbare Verzögerung.
|
||||||
|
- Zugänge zur Sitzungsliste und zum Funktionswechsel bleiben auch in dieser
|
||||||
|
Funktion erreichbar (Anzeige der Funktion antippen, Stapel-Leiste antippen).
|
||||||
|
- Gegenprobe der Grenzen (siehe „Grenzen" oben): Teile eng aneinanderlegen
|
||||||
|
(Hochrechnung), Teile stapeln (nur oberste Schicht zählt), einseitige
|
||||||
|
Beleuchtung, geringer Kontrast zum Untergrund — beobachten, wo die Zahl
|
||||||
|
spürbar daneben liegt, bisher nur an synthetischen Testbildern geprüft, nie
|
||||||
|
an einem echten Foto.
|
||||||
- Verbindung während des allerersten Scans einer Sitzung unterbrechen (WASM
|
- Verbindung während des allerersten Scans einer Sitzung unterbrechen (WASM
|
||||||
lädt per CDN), danach mit wiederhergestellter Verbindung erneut scannen:
|
lädt per CDN), danach mit wiederhergestellter Verbindung erneut scannen:
|
||||||
Das muss einen echten neuen Ladeversuch auslösen statt dauerhaft mit
|
Das muss einen echten neuen Ladeversuch auslösen statt dauerhaft mit
|
||||||
|
|||||||
Reference in New Issue
Block a user