Doku: voller OCR-Rohtext in "Text erkennen" (Rahmen, Whitelist, Anzeige)
README auf den aktuellen Stand gebracht: Zielrahmen ist jetzt auch in "Text erkennen" wirksam (grabFrameRegion statt grabFrame), breitere Zeichen- Whitelist samt Abwägung, additiver OCR-Rohtext (rawText) in Pipeline, Speicherung und Anzeige, wartende statt automatisch ausblendende Rückmeldung in "Text erkennen". Datei-Tabelle, Abschnitt "Sitzungssicherung im Detail", "Grenzen" und die manuelle Geräte-Prüfliste entsprechend ergänzt; Testanzahl 144 → 154.
This commit is contained in:
@@ -80,9 +80,14 @@ keine Daten verlassen das Gerät.
|
||||
„QR-Code" sucht die App ohnehin laufend, ein Knopf ohne Texterkennung hätte
|
||||
dort nichts zu tun. Der Zielrahmen hebt sich in „Strichcode" und „QR-Code"
|
||||
hervor, sobald ein passender Code im Bild ist; in „Text erkennen" bleibt er
|
||||
schlicht, weil dort nichts laufend erkannt wird. Ein Wechsel der Funktion
|
||||
während des Sortierens (z. B. bei gemischter Ware) gilt sofort: laufende
|
||||
Suche startet oder stoppt, der Knopf erscheint oder verschwindet.
|
||||
schlicht, weil dort nichts laufend erkannt wird. Trotzdem ist der Rahmen
|
||||
auch dort wirksam: „Modul scannen" liest genau den Bildausschnitt innerhalb
|
||||
des Rahmens, in voller Kameraauflösung, nicht mehr das gesamte,
|
||||
heruntergerechnete Kamerabild (`grabFrameRegion` in `src/camera.js` —
|
||||
derselbe Ausschnitt, den auch die laufende Barcode-Suche benutzt). Ein
|
||||
Wechsel der Funktion während des Sortierens (z. B. bei gemischter Ware)
|
||||
gilt sofort: laufende Suche startet oder stoppt, der Knopf erscheint oder
|
||||
verschwindet.
|
||||
|
||||
Liegt beim Start eine gesicherte Sitzung vor, erscheint zuerst die Frage
|
||||
nach dem Fortsetzen (siehe Punkt 5 unten) und erst danach die Funktionswahl
|
||||
@@ -123,20 +128,41 @@ keine Daten verlassen das Gerät.
|
||||
3. **Texterkennung** (ausschließlich in „Text erkennen", ausgelöst durch
|
||||
„Modul scannen"). Anders als früher ist das kein automatischer Rückfall
|
||||
vom Barcode-Weg mehr, sondern die einzige Quelle dieser Funktion — sie
|
||||
liest ohnehin nie einen Barcode (siehe Punkt 0). Das Kamerabild wird dafür
|
||||
liest ohnehin nie einen Barcode (siehe Punkt 0). Gelesen wird der
|
||||
Bildausschnitt innerhalb des Zielrahmens, in voller Kameraauflösung
|
||||
(`grabFrameRegion`, siehe Punkt 0) — nicht mehr das ganze, auf 1280 Pixel
|
||||
heruntergerechnete Kamerabild. Das Bild wird dafür
|
||||
in Graustufen gewandelt und mit einem **Otsu-Schwellwert** in Schwarz/Weiß
|
||||
aufbereitet: Der Schwellwert wird aus der Helligkeitsverteilung des
|
||||
gesamten Bildes bestimmt, nicht aus einer festen Kontrastspreizung
|
||||
zwischen hellstem und dunkelstem Pixel. Das macht die Aufbereitung robust
|
||||
gegen einzelne Lichtreflexe auf glänzenden Metalletiketten, die eine reine
|
||||
Min/Max-Spreizung leicht kippen würden. Das OCR-Ergebnis wird anschließend
|
||||
gegen die bekannten Spec-Werte abgeglichen, was die typischen
|
||||
Verwechslungen (0/O, 1/I, 8/B, …) auflöst. Da in dieser Funktion nie eine
|
||||
per Barcode gelesene Teilenummer vorliegt, entscheiden hier ausschließlich
|
||||
die aus dem erkannten Text abgeleiteten technischen Angaben (Kapazität,
|
||||
Bauform, Rank, Geschwindigkeit) über die Stapelzuordnung
|
||||
(`specsCompatible` in `src/spec.js`) — anders als in „Strichcode"/
|
||||
„QR-Code", wo meist die exakte Teilenummer trägt.
|
||||
Min/Max-Spreizung leicht kippen würden. Die Zeichen-Whitelist von
|
||||
Tesseract (`tessedit_char_whitelist` in `src/ocr.js`) lässt Groß- **und**
|
||||
Kleinbuchstaben, Ziffern sowie die auf Etiketten üblichen Satz- und
|
||||
Sonderzeichen zu — nicht mehr nur Großbuchstaben. Das OCR-Ergebnis wird
|
||||
anschließend gegen die bekannten Spec-Werte abgeglichen, was die
|
||||
typischen Verwechslungen (0/O, 1/I, 8/B, …) auflöst; das kann durch die
|
||||
breitere Whitelist bei den Codeteilen (Kapazität, Rank, Geschwindigkeit,
|
||||
Teilenummer) etwas an Genauigkeit kosten, weil Tesseract jetzt z. B.
|
||||
zwischen „O“ und „o“ unterscheiden muss — eine bewusst in Kauf genommene
|
||||
Abwägung, damit der vollständige Etikettentext lesbar wird. Da in dieser
|
||||
Funktion nie eine per Barcode gelesene Teilenummer vorliegt, entscheiden
|
||||
hier ausschließlich die aus dem erkannten Text abgeleiteten technischen
|
||||
Angaben (Kapazität, Bauform, Rank, Geschwindigkeit) über die
|
||||
Stapelzuordnung (`specsCompatible` in `src/spec.js`) — anders als in
|
||||
„Strichcode"/„QR-Code", wo meist die exakte Teilenummer trägt.
|
||||
|
||||
Der vollständige, ungefilterte Erkennungstext (nicht nur die daraus
|
||||
verstandenen Felder) wird zusätzlich mitgeführt (`recognize` in
|
||||
`src/pipeline.js` liefert ihn als `rawText` zurück) und je Eintrag
|
||||
gespeichert — rein additiv, ohne jeden Einfluss auf die Stapelzuordnung
|
||||
(siehe „Grenzen" unten). In Funktion „Text erkennen" bleibt die
|
||||
Treffer-Rückmeldung deshalb stehen, bis der Nutzer sie wegtippt, und zeigt
|
||||
den vollen erkannten Text an, statt sich nach gut einer Sekunde von selbst
|
||||
auszublenden wie in den beiden Barcode-Funktionen (`showResult` in
|
||||
`src/ui/result-overlay.js`). Der Rohtext jedes Eintrags lässt sich später
|
||||
auch in der Sitzungsliste nachlesen.
|
||||
4. **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)
|
||||
@@ -187,12 +213,15 @@ korrekt funktioniert.
|
||||
npm test
|
||||
```
|
||||
|
||||
144 Tests, alle grün (Stand dieses Dokuments). Getestet werden ausschließlich
|
||||
154 Tests, alle grün (Stand dieses Dokuments). Getestet werden ausschließlich
|
||||
die reinen Module ohne Browser-Zugriff: Teilenummer-Decoder, Spec-Normalisierung
|
||||
und toleranter Vergleich, OCR-Bildaufbereitung (Otsu-Schwellwert) und
|
||||
-Feldextraktion, Stapel-Zuweisung, die Erkennungs-Pipeline samt Zeitgrenzen
|
||||
und Mehrdeutigkeitsbehandlung, die Sitzungssicherung samt Prüfung eines
|
||||
wiederhergestellten Zustands, die drei Scan-Funktionen (`scan-modes.js` —
|
||||
-Feldextraktion, Stapel-Zuweisung, die Erkennungs-Pipeline samt Zeitgrenzen,
|
||||
Mehrdeutigkeitsbehandlung und dem additiven OCR-Rohtext (`rawText` wird nur
|
||||
zurückgegeben, wenn die Texterkennung tatsächlich lief, und beeinflusst
|
||||
nachweislich nie die Stapelzuordnung), die Sitzungssicherung samt Prüfung
|
||||
eines wiederhergestellten Zustands (einschließlich `entry.rawText`), die drei
|
||||
Scan-Funktionen (`scan-modes.js` —
|
||||
Codearten je Funktion, DataMatrix/Aztec/PDF417 in „QR-Code") sowie die je Funktion
|
||||
tatsächlich aufgerufenen Adapter (`scan-recognition.js` — Texterkennung läuft
|
||||
nachweislich nie in „Strichcode"/„QR-Code", Barcode-Dekodierung nachweislich
|
||||
@@ -263,19 +292,19 @@ worauf du bei der Veröffentlichung achten solltest.
|
||||
| `src/pn-decoder.js` | Teilenummer → 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/pipeline.js` | Barcode → Teilenummer → OCR → Ampelfarbe, inkl. Zeitgrenzen, Mehrdeutigkeitsbehandlung und Kurzschluss über einen bereits bekannten Barcode-Inhalt (`deps.isKnownCode`) — unverändert; kennt keine Scan-Funktionen |
|
||||
| `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-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/storage.js` | Absturzschutz der laufenden Sitzung: sichert und lädt aus `localStorage`, verwirft beim Laden jeden in sich unstimmigen Zustand vollständig (siehe unten) |
|
||||
| `src/camera.js` | Kamerastart, Einzelbildaufnahme, Bilddatei-Ersatzweg |
|
||||
| `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/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` |
|
||||
| `src/ocr.js` | Bildaufbereitung (Otsu) 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/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/result-overlay.js` | Kurze Treffer-Rückmeldung (grün/gelb), blendet sich nach kurzer Zeit selbst wieder aus |
|
||||
| `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/resume-dialog.js` | Dialog beim Start: gesicherte Sitzung fortsetzen oder verwerfen — läuft vor der Funktionswahl |
|
||||
| `src/ui/session-list.js` | Sitzungsliste: Stapel-Übersicht, Umsortieren, Entfernen, Sitzung beenden |
|
||||
| `src/ui/session-list.js` | Sitzungsliste: Stapel-Übersicht, Umsortieren, Entfernen, Sitzung beenden, Anzeige des vollständigen OCR-Rohtexts je Eintrag (sofern vorhanden) |
|
||||
| `src/ui/describe-spec.js` | Gemeinsame Kurzbeschreibung eines Specs (Kapazität, Rank, Geschwindigkeit, Bauform), wahlweise mit Platzhaltern für fehlende Felder; von Treffer-Rückmeldung, „Zuletzt"-Zeile und Sitzungsliste gemeinsam genutzt |
|
||||
| `src/main.js` | Verdrahtung aller Module zur lauffähigen App |
|
||||
| `src/styles.css` | Farbvariablen (Grün/Gelb/Rot der Ampel-Rückmeldung), Layout des Kamera-Vollbilds samt Zielrahmen, Stapel-Leiste und Aktionsknöpfe sowie die Overlays für Treffer-Rückmeldung, Rot-Dialog und Sitzungsliste |
|
||||
@@ -309,6 +338,14 @@ Zeichenketten); ein gesicherter Stand aus einer Fassung vor dieser Erweiterung
|
||||
ohne diese Felder gilt dagegen nicht als unstimmig, sondern wird beim Laden
|
||||
als Stapel bzw. Eintrag ohne bekannte Codes wiederhergestellt.
|
||||
|
||||
Nach demselben Muster ist `entry.rawText` (der volle OCR-Rohtext, siehe
|
||||
„Funktionsweise" oben) optional: Ist er vorhanden, muss er eine Zeichenkette
|
||||
sein; ein gesicherter Stand aus einer Fassung vor dieser Erweiterung ohne
|
||||
dieses Feld gilt nicht als unstimmig und wird beim Laden als Eintrag ohne
|
||||
Rohtext (leere Zeichenkette) wiederhergestellt. Anders als `stack.codes` wird
|
||||
`entry.rawText` beim Laden nicht neu abgeleitet — er hängt an genau diesem
|
||||
Eintrag und fließt in keine Stapel-Berechnung ein.
|
||||
|
||||
## Grenzen
|
||||
|
||||
- Keine Bestandsführung über Sitzungen hinweg, kein Export. Die Sicherung in
|
||||
@@ -346,6 +383,13 @@ als Stapel bzw. Eintrag ohne bekannte Codes wiederhergestellt.
|
||||
Validierung braucht deshalb echte Module, keine Code-Prüfung.
|
||||
- Farb- und Schriftgestaltung ist bewusst schlicht gehalten und kann nach dem
|
||||
ersten Einsatz am Tisch nachgezogen werden.
|
||||
- Der volle OCR-Rohtext (`rawText`) dient ausschließlich der Anzeige für den
|
||||
Nutzer (Treffer-Rückmeldung, Sitzungsliste). Die Stapelzuordnung stützt
|
||||
sich bewusst weiterhin ausschließlich auf die daraus abgeleiteten,
|
||||
verstandenen Spec-Felder — roher Erkennungstext schwankt zwischen
|
||||
Aufnahmen (Zeilenumbrüche, zusätzlich erkannte Wörter, Groß-/
|
||||
Kleinschreibung, …) und würde als Gruppierungsmerkmal für praktisch jedes
|
||||
Modul einen eigenen Stapel erzeugen.
|
||||
|
||||
## Herstellertabellen erweitern
|
||||
|
||||
@@ -404,7 +448,11 @@ werden:
|
||||
halten: ebenfalls Treffer.
|
||||
- „Text erkennen" wählen: kein automatisches Hervorheben des Rahmens (er
|
||||
bleibt durchgehend schlicht), „Modul scannen"-Knopf sichtbar und löst die
|
||||
Texterkennung aus.
|
||||
Texterkennung aus. Der Rahmen ist dort trotzdem wirksam: nur der
|
||||
Bildausschnitt innerhalb des Rahmens wird gelesen (nicht das ganze
|
||||
Kamerabild) — mit Text außerhalb des Rahmens auf demselben Etikett prüfen,
|
||||
dass er **nicht** erkannt wird, während Text innerhalb des Rahmens
|
||||
vollständig erscheint.
|
||||
- Anzeige der gewählten Funktion in der Scan-Ansicht antippen: Auswahl
|
||||
erscheint erneut, nach der Wahl gilt der Wechsel sofort — laufende Suche
|
||||
startet/stoppt, Knopf erscheint/verschwindet, **ohne** die Seite neu zu
|
||||
@@ -418,7 +466,21 @@ werden:
|
||||
- In Funktion „Text erkennen" ein Etikett fotografieren und „Modul scannen"
|
||||
antippen: die Otsu-Aufbereitung liefert auf einem echten, glänzenden
|
||||
Etikettenfoto tatsächlich brauchbaren Text (bisher nur an synthetischen
|
||||
Testbildern geprüft, nie an einem echten Foto).
|
||||
Testbildern geprüft, nie an einem echten Foto). Prüfen, dass die
|
||||
Rückmeldung dabei den **vollständigen** erkannten Text zeigt (Groß- und
|
||||
Kleinbuchstaben, nicht nur die von der App verstandenen Felder wie
|
||||
`32GB 2Rx4 PC4-2666`), stehen bleibt, bis sie weggetippt wird, und bei
|
||||
langem Text lesbar bleibt (per Scrollen erreichbar, wächst nicht aus dem
|
||||
Bildschirm heraus). Danach in der Sitzungsliste nachsehen, dass derselbe
|
||||
Rohtext beim Eintrag zum Nachlesen erscheint.
|
||||
- Da der Bildausschnitt für die Texterkennung jetzt deutlich größer ist als
|
||||
das bisher übergebene, auf 1280 Pixel herunterskalierte Vollbild
|
||||
(`grabFrameRegion` statt `grabFrame`, siehe „Funktionsweise"), dauert ein
|
||||
einzelner Erkennungsversuch länger als vorher — beobachten, wie lange ein
|
||||
normaler Scan auf einem durchschnittlichen Handy tatsächlich braucht, und
|
||||
ob er dabei spürbar unter der 20-Sekunden-Zeitgrenze der Pipeline bleibt
|
||||
(siehe dazu auch den folgenden Punkt zur Ladezeit des Tesseract-Arbeiters,
|
||||
die zusätzlich in dieselbe Zeitgrenze fällt).
|
||||
- Ladezeit des WASM-Barcode-Moduls (`zxing-wasm`) beim allerersten Scan einer
|
||||
Sitzung in Funktion „Strichcode" oder „QR-Code" beobachten — bleibt sie
|
||||
deutlich unter der 10-Sekunden-Zeitgrenze der Pipeline, und braucht ein
|
||||
@@ -440,8 +502,11 @@ werden:
|
||||
Ladevorgang dauerhaft "verfügbar", springt nach einem erzwungenen
|
||||
Fehlschlag (z. B. Flugmodus beim ersten Laden) beim nächsten Erfolg wieder
|
||||
darauf zurück?
|
||||
- Stichprobe, ob die feste Zeichen-Whitelist der Texterkennung auf echten
|
||||
Etiketten keine tatsächlich benötigten Zeichen ausschließt.
|
||||
- Stichprobe, ob die Zeichen-Whitelist der Texterkennung (Groß-/
|
||||
Kleinbuchstaben, Ziffern, übliche Satz-/Sonderzeichen) auf echten Etiketten
|
||||
keine tatsächlich benötigten Zeichen ausschließt, und ob die Erkennung der
|
||||
Codeteile (Kapazität, Rank, Geschwindigkeit, Teilenummer) durch die jetzt
|
||||
mögliche Groß-/Kleinschreibung noch verlässlich genug bleibt.
|
||||
- Funktion „Strichcode"/„QR-Code": kein passender Code im Bild führt zu
|
||||
Rot-Dialog (statt Fehler oder Absturz) — hier ohne jeden OCR-Versuch.
|
||||
Funktion „Text erkennen": kein verwertbarer OCR-Text führt ebenfalls zu
|
||||
@@ -461,9 +526,15 @@ werden:
|
||||
es passend.
|
||||
- Stapel-Leiste (`A: 12`, `B: 4`) aus rund einem Meter Entfernung mit einer
|
||||
Hand lesbar.
|
||||
- Grüne/gelbe Rückmeldung erscheint nach dem Scan und verschwindet nach
|
||||
rund 1200 ms von selbst; bei zwei Scans deutlich unter 1200 ms Abstand
|
||||
bleibt jeweils nur eine Rückmeldung sichtbar und die App bleibt bedienbar.
|
||||
- In „Strichcode"/„QR-Code": Grüne/gelbe Rückmeldung erscheint nach dem Scan
|
||||
und verschwindet nach rund 1200 ms von selbst; bei zwei Scans deutlich
|
||||
unter 1200 ms Abstand bleibt jeweils nur eine Rückmeldung sichtbar und die
|
||||
App bleibt bedienbar.
|
||||
- In „Text erkennen": Rückmeldung bleibt stehen, bis sie über die
|
||||
„weiter"-Schaltfläche (mindestens 56px hoch) weggetippt wird — kein
|
||||
automatisches Ausblenden. Ein weiterer Scan, bevor die vorherige
|
||||
Rückmeldung weggetippt wurde, ersetzt sie sofort durch die neue, ohne die
|
||||
App dauerhaft zu sperren.
|
||||
- Alle Bedienflächen (Scan-, Rückgängig-, Stapel-Knöpfe) mit dem Daumen
|
||||
erreichbar, während die andere Hand das Modul hält.
|
||||
- Rückgängig-Knopf: Screenreader liest "Letzten Scan zurücknehmen" vor.
|
||||
|
||||
Reference in New Issue
Block a user