# OCR - Rechnungserkennung, wie geht das genau?



## beta20 (19. Nov 2018)

Hallo zusammen, 

ich würde gerne eine automatische Rechnungserkennung programmieren.
Ich frage mich jedoch gerade wie das technisch genau abläuft, wie erkennt mein OCR den Rechnungsbetrag, Datum etc.?

Hier meine Idee...
1) Ich scanne ein PDF / Image ein
2) Jage das über den OCR (z.B. Tessa4j OCR).
3) Nun erhalte ich einen String zurück
4) Ich prüfe den String nun auf verschiedene String ab (z.B. "Rechnungsdatum", "Rechnungsbetrag"; dahinter sollte dann i.d.R. der Rechnungsbetrag etc. stehen...
5) Wie erhalte ich den Betrag / Datum aber nun?

Danke für jede Hilfe.


----------



## httpdigest (19. Nov 2018)

Das Ganze kann sich von relativ einfach bis seeehr seeehr schwer gestalten. Angenommen, das PDF verwendet eine Art tabellarischen Aufbau der Rechnungspositionen mit Linien hier und dort und dem tatsächlichen Rechnungsbetrag unter irgendeiner doppelt gestrichelten Linie (die z.B. vom OCR Tool als mehrere Gleichheitszeichen interpretiert werden könnte).
Es hängt zu 100% von dem tatsächlich verwendeten Image/PDF ab und auch von den OCR Einstellungen (z.B. DPI, ob nur Text oder auch Bilderkennung, etc.).
Du musst es also einfach mal ausprobieren und "gucken", was für ein String da dann herauskommt. Dann kannst du dir z.B. einen regulären Ausdruck überlegen, oder einfach per string.indexOf("Rechnungsbetrag") den Index im Text heraussuchen und dann mit einem Offset den Wert extrahieren, falls dieser denn dahintersteht.

Optimalerweise sollte man aber für Maschine-zu-Maschine Kommunikation ein strukturiertes Datenformat, z.B. XML oder JSON, verwenden. PDFs sind ja eher für Maschine-zu-Mensch Kommunikation gedacht: Maschine druckt PDF aus -> Mensch interpretiert den Inhalt. Falls das System, was dir das PDF generiert, also solch eine Schnittstelle anbietet, ist das auf jeden Fall zu bevorzugen.


----------



## mihe7 (19. Nov 2018)

Da kann @httpdigest nur uneingeschränkt Zustimmen. Wir haben das mal mit PDFs versucht, in denen die Zeichen (keine Zeichenketten!) sogar extrahiert werden konnten. Die Dinger waren nicht gescannt sondern erzeugt worden.

Man konnte also eine Liste von Positionsangaben und dem dazugehörigen Zeichen erhalten. Selbst da ist es ein Ding der "Unmöglichkeit", einen einfachen Algorithmus anzugeben, der das Problem löst.

Das fängt schon damit an, dass die Wortabstände teilweise nicht von Zeichenabständen zu unterscheiden sind. Die Bündigkeit von Spalten in Tabellen ist ebenfalls kaum zu erkennen. Rechtsbündigen Zellen sind mit den Daten überhaupt nicht erkennbar, weil im PDF die Koordinate von links angegeben wird usw. Dann gibt es das Problem, dass Tabellen über mehrere Seiten gehen etc. etc.

Man muss also eine gehörige Portion Aufwand in die Sache stecken, um eine Lösung zu finden.

Es gibt allerdings Tools, die in der Lage sind, einen Scan z. B. in ein Word- oder Excel-Dokument umzuwandeln. Wenn das gut funktioniert, kann man damit natürlich weiterarbeiten.


----------



## beta20 (19. Nov 2018)

Ok, danke.

Ich brauche den Scan nicht als Word / Excelfile.
Ich will lediglich aus dem Scan / Datei die verschiedenen Informationen aus einer Rechnung herausbekommen (Betrag, Datum...).
Was ich mich nun allerdings frage, lohnt sich der Aufwand überhaupt das selbst zu programmieren?
Es gibt doch sicherlicht Dienste mittlerweile, die das für einen übernehmen können, die man dann mit einer REST API ansprechen kann? Oder sieht ihr das anderst?


----------



## mihe7 (19. Nov 2018)

beta20 hat gesagt.:


> Es gibt doch sicherlicht Dienste mittlerweile, die das für einen übernehmen können, die man dann mit einer REST API ansprechen kann?


Ich wage zu bezweifeln, dass es schon einen Dienst gibt, dem Du irgendeinen Scan zuschickst und der Dir dann Anwortet: Hey, das ist eine Rechnung. Die hat die Nummer 421 vom Kunden X, geschrieben am 12.12.2017, mit einem Gesamtbetrag von 123 €. In Position 1 - der Kaffeemaschine - sind 19 % MwSt enthalten. Überwiesen soll der Betrag auf die IBAN DExxxxx werden. Dabei ist als Verwendungszweck 2421/421 anzugeben, der Geschäftsführer ist der Bürgermeister Krause, geliefert werden soll aber an den Hausmeister... aber wer weiß, vielleicht ist die KI ja schon so weit 

Was ich weiß: es gibt Dienste (wie auch Programme), mit denen man ein PDF z. B. in Text, Excel, ... umwandeln kann. Ob die einen Webservice anbieten, weiß ich nicht. Die benötigten Daten musst Du Dir dann selbst rausziehen.


----------



## beta20 (19. Nov 2018)

Es gibt Programm (z.B. SevDesk), die machen sowas doch schon (ausgenommen die automatische Überweisung)

Prinzipiell brauche ich ja "nur":
a) Den String der PDF (Scan)
b) Funktion, die mir dann bestimmte Typen inkl. Wert liefert: also z.B. :
-> Suche ich nach "*Rechnungsbetrag*" in meinem String (den ich vom Scan erhalte), dann soll eben der entsprechende *Wert (5,00 EUR*) zurückgegeben. 

Also sowas wie: 

```
public String findValue(String value) {
....
}
```
-> Value ist dann der komplette String, den ich dann durch den OCR zurückbekomme.

Mein Problem ist Stand heute den *Wert *zu bekommen (also z.B. *"5,00EUR"* von "Rechnungsbetrag").


----------



## Axolis (19. Nov 2018)

Hey, beta20.
Ich programmiere im Augenblick genau eine solche Geschichte als interne Software in einem Unternehmen.
Besonders bei der Ermittlung des Rechnungsbetrages kannst Du mit "gewöhnlichen" Mitteln wie String.contains() oder anderen "einfachen" Parsingversuchen nicht viel anfangen, da Du (wie hier auch schon gesagt wurde) nie wissen kannst, wo genau der Betrag jetzt steht. Manchmal erhältst Du sicher "Rechnungsbetrag EUR 5,00". meistens wird es aber irgendwie anders sein.
- es steht nichts vor dem gesuchten Wert
- es steht ein anderes Wort davor (Betrag, Summe, gesamt, total, Saldo, ...)
- Der Wert steht nicht in derselben Zeile wie das Wort "Rechnungsbetrag"
usw usw usw.
Da braucht es schon heftigere Geschütze, um ein solches Muster zu erkennen...

Grüße,
Axolis


----------



## mihe7 (19. Nov 2018)

beta20 hat gesagt.:


> Es gibt Programm (z.B. SevDesk), die machen sowas doch schon (ausgenommen die automatische Überweisung)


Stimmt. Es gibt auch Banken, die damit werben, dass man eine Überweisung per Foto von der Rechnung ausführen kann... Ich wage aber auch hier zu bezweifeln, dass das immer vollautomatisch funktioniert. 

Worum es mir geht ist einfach folgendes: je unterschiedlicher die Rechnungen aufgebaut sind, um so komplizierter wird die Geschichte. Man kommt ziemlich schnell an den Punkt, wo es mit "einfachen Abfragen" nicht mehr weitergeht.

Wenn Du Dir eine Rechnung anschaust und Dir als String vorstellst, dann könnte z. B. bei der einen Rechnung "Rechnungsbetrag: 5,00 €" stehen, bei der nächsten dagegen "Gesamtbetrag    MwSt\n        5,00 €       0,95 €" und das sind noch die einfachen Geschichten.


----------



## beta20 (19. Nov 2018)

Hi Axolis, 
danke für deine Antwort. 
Dass das nicht immer 100% funktioniert, ist mir auch klar - da es immer wieder Ausnahmen geben wird.
Angefangen von anderen Wörtern: (Betrag, Summe, gesamt, total, Saldo, ...)



Axolis hat gesagt.:


> Da braucht es schon heftigere Geschütze, um ein solches Muster zu erkennen...
> Grüße,
> Axolis


Was genau meinst du damit? Wie gehst du das Ganze an?


----------



## Meniskusschaden (19. Nov 2018)

beta20 hat gesagt.:


> 5) Wie erhalte ich den Betrag / Datum aber nun?


Die Rechnungen können je nach Lieferant ja sehr unterschiedlich aussehen. Deshalb würde ich auf jeden Fall eine konfigurierbare Lösung vorsehen, die es ermöglicht, zunächst den Lieferanten zu erkennen, damit das Extrahieren der Inhalte dann spezifisch für den Lieferanten erfolgen kann. Dabei würde ich nicht nur feste Zeichenfolgen, sondern unbedingt auch reguläre Ausdrücke zulassen, die man auf den OCR-Text anwendet. Damit kann man oft eine ganze Menge erreichen. So könnte man beispielsweise anhand der Umsatzsteuer-ID DE123456789 den Lieferanten X zuverlässig identifizieren, bei dessen Rechnungen über den regulären Ausdruck `\b\d{4}\/\d{6}\b` etwa die Rechnungsnummer 2018/123456 erkannt wird, die immer zwei Wörter links vom Rechnungsdatum steht. Für Rechnungsbeträge bietet sich eine Zusatzfunktion an, die typische Währungsbeträge erkennt und darunter den höchsten auswählt. Wenn man dann noch die Netto- und/oder MWSt.-Beträge ausliest kann man durch eine einfache Rechnung feststellen, ob der Betrag praktisch sicher stimmt oder möglicherweise falsch sein kann.


----------



## stg (19. Nov 2018)

Ganz viel der "automatiersten Rechnungserkennung" erfolgt selbst bei professionellen, kommerziellen Lösungen, immer noch per Post nach Fern-Ost 



beta20 hat gesagt.:


> Dass das nicht immer 100% funktioniert, ist mir auch klar -



Wenn du jetzt selbst etwas schreibst sollte deine Erwartungshaltung eher die sein, "dass es ab und an mal funktioniert ... vielleicht".



beta20 hat gesagt.:


> Was ich mich nun allerdings frage, lohnt sich der Aufwand überhaupt das selbst zu programmieren?
> Es gibt doch sicherlicht Dienste mittlerweile, die das für einen übernehmen können, die man dann mit einer REST API ansprechen kann? Oder sieht ihr das anderst?



Gibt es, aber alles was ich kenne kostet die ein oder andere Mark....
Wenn du dich auf wenige, klar definierte "Rechnungsdesigns" beschränkst, dann könnte das klappen (du hast z.B. nur drei Lieferanten, deren Rechnung immer gleich aufgebaut ist)
Wenn es allerdings eine "allgemeine" Lösung werden soll, dann kannst du es quasi vergessen. Es gibt ganze Unternehmen, die sich genau um solche Aufgaben kümmern und schon jahr(zehnt)e-lang, an ihren immer noch nicht vollständig ausgereiften Lösungen arbeiten...


----------



## Thallius (19. Nov 2018)

Mal ein ganz anderer Ansatz. Man nehme alle Beträge in der Rechnung und merke sich die Position. Dann testet man wie sich die zueinander verhalten. Also z.b. Von oben nach unten addieren bis die Summe irgendeinem weiter unten stehenden wert entspricht. Dann hat man die endsumme. Nun noch schauen ob diese die höchste Summe ist. Wenn nicht sucht man noch nach der MwSt Summe die dann die höchste Summe ergibt. Auf die gleiche Weise kann man nach Rabatten suchen etc. 
Ist Aufwendung und fast schon bischen KI könnte aber klappen 

Gruß 

Claus


----------



## Xyz1 (19. Nov 2018)

beta20 hat gesagt.:


> wie erkennt mein OCR den Rechnungsbetrag, Datum etc


- Textblöcke erkennen (Pos. oder Index) [s.g. 'Template matching']
- in Zahlen umwandeln
oder:
- in Zahlen umwandeln
- Textblöcke erkennen (Pos. oder Index) [s.g. 'Template matching']

Iss nicht schwer habe ich kürzlich mal gemacht kann aber durchaus 15 Sek. dauern....
oder Cloud computing/SaaS: bspw. https://ocr.space/ocrapi


----------



## mrBrown (19. Nov 2018)

Thallius hat gesagt.:


> Man nehme alle Beträge in der Rechnung und merke sich die Position.


Das man einen einzelnen Betrag nicht vernünftig erkennt, umgeht man, indem man N Beträge versucht zu erkennen und in Relation zueinander zu setzen? 

Ist das Multiply and surrender?


----------



## Meniskusschaden (19. Nov 2018)

Thallius hat gesagt.:


> Mal ein ganz anderer Ansatz.


Bei dem Ansatz finde ich zwei Dinge schwierig:
1. Man benötigt Strukturinformationen, um zu erkennen, welche Werte übereinander stehen.
2. Man verarbeitet ziemlich viele Werte, so dass die Wahrscheinlichket, dass OCR-Fehler enthalten sind, relativ hoch ist.

Deshalb würde ich lieber versuchen, ob der ganz primitive Ansatz nicht vielversprechender ist: Der OCR-Text wird nur als flache Zeichenfolge aufgefasst. in der es kein oben und unten gibt, sondern nur ein links und rechts. Darin versucht man dann anhand von Mustern seine Ankerpunkte zu finden. Ein Customizing pro Lieferant wird man vermutlich ohnehin machen müssen.


----------



## Tarrew (19. Nov 2018)

Hab über ein ähnliches Thema meine Bachelorarbeit geschrieben und finde den Ansatz, mit gewissen Strukturinformationen zu arbeiten, nicht schlecht.

Ein ganzes Bild in Tesseract zu hauen und dann den versuchen den Output irgendwie zu interpretieren ist mMn. fast unmöglich. Vor allem sobald Zahlen und Texte in Tabellen stehen, irgendwelche Querbalken vorhanden sind etc, kriegt man viel Müll oder garnichts aus Tesseract raus.

Als einfache Variante würde ich mal probieren OpenCV zu verwenden, um Textbausteine zu erkennen (z.B. EAST text detection). Die gefundenen Texte haut man dann jeweils in Tesseract.
Danach kann man dann evtl. mit gewissen Heuristiken arbeiten. Wenn du ein bestimmes Schlüsselwort a la "Rechnungsbetrag" oder Ähnliches findest und entsprechend die Koordinaten der Box hast, würde ich davon ausgehen, dass der Betrag irgendwo rechts, bzw. unterhalb vorhanden ist. Also xBetrag >= xRechnungsbetragString & yBetrag >= yRechnungsbetragString.

Je "näher" am gefundenen String eine Zahl dann ist, desto warscheinlicher vermutlich die Zugehörigkeit.

Bin zwar am Ende auch in die KI-Schiene gerutscht, aber mit dem "primitiven" Ansatz ließen sich schon akzeptable Ergebnisse verzeichnen. Natürlich nicht mit einer Genauigkeit, mit der man es zuverlässig & kommerziell hätte einsetzen können


----------



## Meniskusschaden (19. Nov 2018)

@Tarrew : Der TE will ja nur Rechnungsbetrag und Rechnungsdatum haben. Dafür scheint mir das etwas überdimensioniert zu sein. Wenn man aber beispielsweise die Rechnungsdaten positionsweise verbuchen lassen wollte, wäre das eine ganz andere Geschichte für die man wahrscheinlich so einen Weg gehen müsste.


----------



## Tarrew (19. Nov 2018)

Ich denke nur gerade daran, dass viele Rechnungen in Tabellenform sind, Symbole aufweisen, Querbalken etc.
So ein Bild unverarbeitet einfach in Tesseract reinzuschmeissen ist schon mutig.

Tesseract schafft es nicht Text auszulesen, der innerhalb von Boxen oder irgendwelchen Formen ist.
Irgendeine Form von Vorverarbeitung wird man in solchen Fällen also ohnehin machen müssen.
Evtl. Line-Removal mit Leptonica etc, aber dann ist OpenCV nicht mehr weit weg und auch nicht viel komplizierter.

Wäre natürlich schick mal 2, 3 Musterrechnungen zu sehen, um mal einen Eindruck davon zu bekommen.


----------



## Xyz1 (19. Nov 2018)

Tarrew hat gesagt.:


> Vor allem sobald Zahlen und Texte in Tabellen stehen, irgendwelche Querbalken vorhanden sind etc, kriegt man viel Müll oder garnichts


Wieso dass denn? Du hast doch schon was von Text respektive Zeichenerkennung gehört nehme ich an? Buchstaben und Ziffern lassen sich relativ schnell ausfindig machen und Zeichen eindeutig erkennen.... und zwar besser als ich sie erkennen kann



Tarrew hat gesagt.:


> Wäre natürlich schick mal 2, 3 Musterrechnungen zu sehen, um mal einen Eindruck davon zu bekommen


Erstelle Dir doch ein paar, es gibt für sowas kein einheitliches Format jeder Handwerker kann das selbst machen....

Oben steht meist irgendein name, in der mitte die RechnungsPositionen und unten rechts das was sie Dir abziehen....

Mit diesen Informationen ist ein customizing fast hinfällig.


----------



## Axolis (19. Nov 2018)

Es gibt Tricks, Workarounds, Methoden.
ich arbeite mit zonaler Erkennung, Mustererkennung, Textanalyse, und noch einem gerüttelt Maß reiner Magie...

es bleibt schwer ! 

VG, 
Axolis.


----------



## Meniskusschaden (19. Nov 2018)

Tarrew hat gesagt.:


> Tesseract schafft es nicht Text auszulesen, der innerhalb von Boxen oder irgendwelchen Formen ist.


Ich weiß jetzt nicht, was hier mit Boxen gemeint ist und habe deshalb eben mal testweise eine Papierrechnung eingescannt, deren Summenbereich sich in einem umrandeten Bereich befindet, der noch ein wenig untergliedert ist. Den enthaltenen Text hat Tesseract schon recht gut erkannt. Vielleicht meinst du mit den Boxen aber auch etwas komplizierteres - etwa mit farbigem oder schraffierten Hintergrund oder so. Das wäre meines Erachtens aber eher untypisch für Rechnungen.


----------



## Meniskusschaden (19. Nov 2018)

Tarrew hat gesagt.:


> Wäre natürlich schick mal 2, 3 Musterrechnungen zu sehen, um mal einen Eindruck davon zu bekommen.


Das lässt sich natürlich wirklich besser mit echten Beispielen diskutieren. Aber nach meiner Erfahrung wird man das zur Einführung für die wichtigsten Lieferanten gemeinsam mit dem Anwender bzw. Kunden einstellen und danach bleibt es eine dauerhafte Aufgabe, sich schlecht erkannte Rechnungen anzusehen und die Konfiguration zu verbessern (oder zu entscheiden, dass es sich für den Lieferanten nicht lohnt). Das sehe ich aber als Aufgabe des Anwenders/Kunden.


----------



## beta20 (20. Nov 2018)

Meniskusschaden hat gesagt.:


> Den enthaltenen Text hat Tesseract schon recht gut erkannt. Vielleicht meinst du mit den Boxen aber auch etwas komplizierteres - etwa mit farbigem oder schraffierten Hintergrund oder so. Das wäre meines Erachtens aber eher untypisch für Rechnungen.


könntest du mal bitte den Code posten?


----------



## Xyz1 (20. Nov 2018)

beta20 hat gesagt.:


> könntest du mal bitte den Code posten?


Erschleichen der Lösungen


----------



## Meniskusschaden (20. Nov 2018)

beta20 hat gesagt.:


> könntest du mal bitte den Code posten?


Welchen Code? Ich habe einfach nur manuell Tesseract für eine gescannte TIF-Datei aufgerufen, weil ich sehen wollte, was die OCR liefert:

```
tesseract -l deu rechnung.tiff rechnung
```


----------



## Senftube (21. Nov 2018)

Such mal im web nach *xpdf* (opensource) dort gibt es in einem Unterverzeichnis auch diverse Kommandzeilenversionen u.a.
z.B eine  pdftotext.exe
mit  der Text im pdf auf eine textdatei extrahiert wird. Das kann man gut in einem java programm
aufrufen. Mit folgends args hab ich die besten erfahrungen gemacht. Die Args hab ich in meiner Anwendung  konfigurierbar gemacht.

s = props.getProperty("PDF_TO_TEXT_ARGS","-eol dos -bom \"{0}\" \"{1}\""); // 0=pdffile 1=outfile 

Die -bom option erzeugt trotzdem kein BOM im outputfile


----------



## beta20 (3. Dez 2018)

Also ich habe Tessa4j jetzt mal installiert. Das funktoniert nun auch soweit.

Folgendes bekomme ich heraus:

```
Karl Klimm
Holleweg 7
12345 DEMOSTEDT
Rechnung
Rechnungsnummer Zahlungsziel ~~ Leistungszeitraum Rechnungsdatum
5be18f9781b1f20928284969 07.11.2018 01.11.2018 00:00- 30.11.2018 23:59 06.11.2018
Bezeichnung (VIET T=4 (Idee MwSt. % VIALS Netto
Einrichtungsgebihr 1 50,00 19 9,50 50,00
01.11.2018 00:00
Mein Produkt - Advanced 1 75,00 19 14,25 75,00
enthalt alle basic-Funktionen plus das Feature Deluxe pro Monat
monatliche Laufzeit und monatliche Zahlung
01.11.2018 00:00 - 01.12.2018 00:00
Gesamt Netto 125,00
MwSt. 19% 23,75
Gesamtbetrag EUR 148,75
```

Wie bekomme ich nun die wirklichen Dinge, die ich brauche.
Beispiel:

```
Gesamtbetrag EUR 148,75
```

-> Nun will ich nur 
Betrag: 148,75
Currency: EUR
....

Wie gehe ich hier voran?


----------



## mihe7 (3. Dez 2018)

```
String line = "Gesamtbetrag EUR 148,75";
String[] parts = line.split(" ");
DecimalFormat df = (DecimalFormat) NumberFormat.getInstance(Locale.GERMAN);
df.setParseBigDecimal(true);
BigDecimal value = (BigDecimal) df.parse(parts[2]);
String currency = parts[1];
```


----------



## Meniskusschaden (3. Dez 2018)

beta20 hat gesagt.:


> Wie gehe ich hier voran?


Z.B. mit regulären Ausdrücken:

```
String regExp = "Gesamtbetrag ([A-Z]{3}) (\\d+,\\d\\d)";     
        int iCurrency = 1;
        int iAmount = 2;

        String text = "vvv yvä vöä g gdfsg dfs Gesamt Netto 125,00 MwSt. 19% 23,75 Gesamtbetrag EUR 148,75";
        Matcher matcher = Pattern.compile(regExp).matcher(text);
        matcher.find();
        System.out.println(matcher.group(iCurrency));
        System.out.println(matcher.group(iAmount));
```
Dann kannst du leicht beliebig viele Regeln in eine Konfigurationsdatei auslagern. Eine Regel könnte aus einem regulären Ausdruck und einer Liste von Gruppenindizes bestehen, die die Gruppen des regulären Ausdrucks dem jeweils entsprechenden Wert zuordnen.
Darüber hinaus könntest du - falls die Rechnungen sich unterscheiden - mehrere solcher Regelsätze definieren und den jeweils passenden - wiederum anhand eines regulären Ausdrucks - vorab auswählen lassen.


----------



## beta20 (4. Dez 2018)

also mein Ansatz ist das als "Machinelearning" aufzuziehen.
Das Programm wird leben und immer mehr erweitert, da die Rechnungen werden auf keinen Fall immer gleich aussehen.

Im Prinzip benötige ich ja immer folgende Informationen:
- Rechnungsnummer
- Rechnungsdatum
- Nettopreis
- Bruttopreis
- Währung
- Fälligkeit

- Lieferant
- BIC
- IBAN
- Straße
- PLZ
- Land

Im groben Ablauf suche ich dann pro Rechnung immer nach diesen Informationen.
Hierzu habe ich dann pro Information eine Funktion


```
public String findRechnungsnummer(String stringFromInvoice){}
public String findRechnungsdatum(String stringFromInvoice){}
```

Folgende Idee schwebt mir vor:
Ich lege mehrere DB-Tabellen an um die Dinge zu ermitteln.

1) Invoice_Regex
   ID,
   Regex,   -> Beispiel: Gesamtbetrag ([A-Z]{3}) (\\d+,\\d\\d)
   Example, -> Beispiel: Gesamtbetrag EUR 126,00
   Type     -> handelt es sich um den Rechnungsbetrag, Rechnungsdatum...
   languageCode -> Sprache

Nun wird bspw. in der Funktion 

```
public String findRechnungsnummer(String stringFromInvoice){}
```

alle Einträge der Tabelle vom Typ "Rechnungsnummer" geholt.
Innerhalb einer Schleife werden dann die Regex durchgegangen:


```
String regExp = entry[i].regex;  
int iCurrency = 1;
int iAmount = 2;
```

-> Sobald es ein Match gibt, wird die Methode beendet und die weitere Informationen der Rechnung werden gesucht...

Eine zweite Tabelle könnte die Lieferanten speichern.
-> Dies könnte dazu dienen, dass man die Branche des Lieferanten und demnach den Typ (Hostinggebühren, Hotelkosten...) direkt vorschlagen kann.

2) Invoice_Vendor
   ID
   Name
   Country
   ...

3) BelegTyp
   Bsp. Hosting, Hotel....

Ist das eine gute Idee das so zu machen oder gibt es andere Vorschläge / Verbesserungen?

Wenn ich das richtig verstehe, ist die Challenge eig. nun die passenden *RegexExpressions *zu erstellen?


----------



## Meniskusschaden (4. Dez 2018)

beta20 hat gesagt.:


> also mein Ansatz ist das als "Machinelearning" aufzuziehen.


Von "Machinelearning" verstehe ich nicht viel. Ich würde da aber mit unverhältnismäßig großem Entwicklungsaufwand rechnen und auch erwarten, dass die Ursachen schlechter Ergebnisse schwieriger zu ermitteln und zu beseitigen sind. Ich bevorzuge eindeutig manuell gepflegte Erkennungsregeln. Bei schlechten Ergebnissen sieht man sich den OCR-Text an und überlegt sich, welche Ausdrücke man etwas tolerenter oder schärfer gestaltet.



beta20 hat gesagt.:


> Im groben Ablauf suche ich dann pro Rechnung immer nach diesen Informationen.
> Hierzu habe ich dann pro Information eine Funktion
> 
> ```
> ...


Ich glaube, das wäre mir vielleicht nicht generisch genug. Ich würde nicht einzeln "Gib mir die Rechnungsnummer!", "Gib mir das Datum!" etc. aufrufen wollen, sondern "Gib mir alles, was du findest!". Aber vielleicht ist dein Weg auch pragmatischer. Für die Inhouse-Programmierung muß nicht immer alles generisch sein.



beta20 hat gesagt.:


> Nun wird bspw. in der Funktion
> 
> ```
> public String findRechnungsnummer(String stringFromInvoice){}
> ...


Ich würde das genau anders herum machen, denn ich finde es nicht sehr erfolgversprechend, einfach alle Möglichkeiten für die Rechnungsnummer durchzuprobieren. Es ist viel zu wahrscheinlich, dass ein Suchmuster, das für Lieferant A gut passt, auch bei Lieferant B matcht, jedoch einen falschen Wert liefert. Es ist schwierig, universelle Regeln zu finden. Es ist aber ziemlich einfach, den Lieferanten zu identifizieren. Und bei sehr vielen Lieferanten wird es auch einfach sein, die gewünschten Infos zu extrahieren, wenn man denn weiß, dass es dieser Lieferant ist.

Also noch einmal mein Vorschlag:

Schritt 1: Den Lieferanten der Rechnung identifizieren.
Das lässt sich leicht mit regulären Ausdrücken bewerkstelligen. Hier wäre auch eine Automatisierung denkbar, wenn man einfach eine ODER-Verknüpfung für die typischen Kandidaten wie Steuernummern, Bankverbindungen, Internet-Domänen etc. aus den ERP-Stammdaten generiert. Es sind aber noch genug Fehlerquellen denkbar, etwa aufgrund unterschiedlicher Formatierungen. Deshalb würde ich auch das zunächst manuell machen und Erfahrungen sammeln.

Schritt 2: Rechnungsdaten nach individuellen Regeln des Lieferanten ermitteln.
Hier würde ich dauerhaft bei manuell erstellten Regeln bleiben. Für diesen Lieferanten gibt es dann nicht x Ausdrücke für das Rechnungsdatum, sondern nur einen, der exakt zugeschnitten ist. Den OCR-Text wird man ja ohnehin mit dem Dokument abspeichern. Bei schlechten Ergebnissen sieht man sich ihn an, prüft die Regeln, passt sie an und ruft einen Refresh auf, um die Werte neu zu ermitteln und damit die Regeln zu prüfen.



beta20 hat gesagt.:


> Wenn ich das richtig verstehe, ist die Challenge eig. nun die passenden RegexExpressions zu erstellen?


Ja. Die eine Hälfte der Funktionalität schenkt einem die OCR, die andere Hälfte die RegEx. Für die eigentliche Verarbeitung ist kaum etwas zu programmieren.


----------



## beta20 (5. Dez 2018)

Danke Dir.

Mit "machinelearning" meine ich auch eher (vllt. ist der Begriff an der Stelle nicht ganz korrekt):
- user scannt Dokument ein
- OCR läuft drüber
- Rechnungsdaten werden nicht erkannt
- User kann über das Bild der Rechnung einen Bereich definieren und dann definieren, das ist meine "Rechnungsnr" z.B.
- Anschließend wird dies in eine Tabelle geschrieben, dass die Rechnung nicht erkannt wurde
- Ein Admin kann dann prüfen, warum diese nicht erkannt wurde und ggf. das Programm erweitern / Tabelleneintrag hinzufügen...

Was verstehst du mit "Inhouse Programmierung" ?

OK, das ist auch ein guter Vorschlag von dir.
Ich verstehe es dann so, dass man in der Lieferanten - Tabelle ebenfalls die Regex - Funktionen der verschiedenen Dinge speichert, sodass man diese bei einer erneuten Rechnung schnell im Zugriff hat?
Natürlich könnte ein Lieferant seine Rechnung ändern, dann müsste man den Eintrag in der Tabelle wieder anpassen...
Ggf. kann ein Lieferant auch mehrere Rechnungsdesign haben.

Also um es zusammenfassen:
1) Lieferant suchen (per Steuernummer / Bankverbindung / Homepage)
2) Prüfen, ob schon in Lieferanttabelle vorhanden
3) Wenn ja: Regex - Funktionen des Lieferant anwenden, die in der Tabelle gespeichert wurde
4) Wenn nein: "allgemeine Regex - Funktionen" anwenden, die aus einer seperaten Tabelle kommen + Lieferant in die Tabelle aufnehmen


Eine weitere Frage noch:
User1:
- scannt Dokument ein
- Lieferant gibt es noch nicht
- Lieferant wird in die DB - Tabelle aufgenommen und und Kategorie "Hotel" gespeichert


User2:
- scannt Dokument vom gleichen Lieferant ein
- Lieferant gibt es schon und die Regex - Funktionen werden verwendet, Rechnungsinfos wird auch erkannt etc.
- User definiert aber eine andere Kategorie "Hoster"

Wie kann ich damit umgehen? Ggf. kann ein Lieferant auch aus unterschiedlichen Branchen kommen.
Sollte ich hier ein Rank anwenden über alle Belege mit dem Lieferanten.
Die Anzahl mit den meisten gleichen Branchen wird dann standardmäßig übernommen?


----------



## VfL_Freak (5. Dez 2018)

Moin


beta20 hat gesagt.:


> Was verstehst du mit "Inhouse Programmierung" ?


https://www.thecodingforums.com/threads/in-house-programming-meaning.135749/

VG Klaus


----------



## Meniskusschaden (5. Dez 2018)

beta20 hat gesagt.:


> User kann über das Bild der Rechnung einen Bereich definieren und dann definieren, das ist meine "Rechnungsnr" z.B.


Solche Funktionen werden den größten Aufwand ausmachen und für mich ist fraglich, ob es wirklich einen großen Nutzen bringt. Es ist ja nicht trivial, daraus eine brauchbare Regel abzuleiten, die das auch bei anderen Rechnungen des Lieferanten erkennt. In der Praxis würde man wahrscheinlich einfach das OCR-Ergebnis in einen RegEx-Tester kopieren, dort einen Ausdruck aufbauen, der für das Beispiel matcht und überlegen, welche Teile wirklich konstant und welche variabel sind. Ich würde erst einmal fast nichts entwickeln, sondern als Proof of Concept die Regeln für ein paar Lieferanten an echten Belegen ausprobieren.



beta20 hat gesagt.:


> Was verstehst du mit "Inhouse Programmierung" ?


Damit meine ich die Programmierung für das eigene Unternehmen und bis zu einem gewissen Grad auch individuelle Auftragsprogrammierung für einen Kunden. Also eben keine Standardsoftware, die für viele Kunden anpassbar sein muss.



beta20 hat gesagt.:


> Ich verstehe es dann so, dass man in der Lieferanten - Tabelle ebenfalls die Regex - Funktionen der verschiedenen Dinge speichert, sodass man diese bei einer erneuten Rechnung schnell im Zugriff hat?
> Natürlich könnte ein Lieferant seine Rechnung ändern, dann müsste man den Eintrag in der Tabelle wieder anpassen...
> Ggf. kann ein Lieferant auch mehrere Rechnungsdesign haben.
> 
> ...



Ich würde es im eigentlichen Kern der Dokumentenverarbeitung vermeiden, direkte Abhängigkeiten zu Lieferantentabellen und ähnlich spezifischen Dingen zu schaffen, denn eigentlich kann man davon ganz unabhängig bleiben und die Funktionalität dann auch für ganz andere Dokumentarten verwenden (oder auch dafür, überhaupt die Dokumentart zu erkennen und unsortierte Eingangspost zu ordnen).
Für mich wäre das Ziel, ein Dokument in die Dokumentenverarbeitung werfen zu können und eine Liste mit Schlüssel/Wert-Paaren zurück zu bekommen. Dieses Ergebnis kann man dann ja im konkreten Kontext der Rechnungsverarbeitung spezifisch weiter verarbeiten. Aber innerhalb der Dokumentenverarbeitung würde ich universell bleiben. Als Beispiel könnten zwei Tabellen genügen:

```
Tabelle PATTERN_SETS:

ID  NAME                 REGEX                      Erläuterung
1   Klimm-Rechnung       Karl Klimm|DE123456789     Identifikation anhand Name oder Umsatzsteuer-ID
2   Mustermann-Rechnung  DE987654321|02\/815\/4711  Identifikation anhand Umsatzsteuer-ID oder Steuernummer


Tabelle PATTERNS:

ID  PATTERN_SET  NAME             REGEX                                  GROUP  Erläuterung
1   1            Rechnungsnummer  (\b\w{24}\b)                           1      Rechnungsnummer für Klimm ist ein Wort aus 24 Zeichen
2   1            Rechnungsdatum   \d\d:\d\d (\d\d\.\d\d\.\d{4})          1      Rechnungsdatum für Klimm ist ein Datum, das auf eine Uhrzeit folgt
3   1            Währung          Gesamtbetrag (\w{3}) (\d+,\d\d)        1      Die Währung für Klimm sind drei Buchstaben zwischen dem Wort "Gesamtbetrag" und einem Betrag
4   1            Betrag           Gesamtbetrag (\w{3}) (\d+,\d\d)        2      Der Betrag für Klimm ist ein Betrag hinter dem Wort "Gesamtbetrag" und der Währung
5   2            Rechnungsnummer  \b(\d{4}-\d{5})\b                      1      Eine Rechnungsnummer für Mustermann könnte so aussehen: 2018-12345
6   2            Rechnungsdatum   Rechnungsdatum.*?(\d\d\.\d\d\.\d{4})   1      Ein Rechnungsdatum für Mustermann könnte das erste Datum nach dem Wort "Rechnungsdatum" sein
```
Man kann das dann ohne Weiteres für ganz andere Dokumentarten benutzen. Es spricht auch nichts dagegen, für einen Lieferanten zwei Regelsätze oder einen Regelsatz für mehrere Lieferanten zu verwenden. Auch mehrere Muster für dasselbe Schlüsselfeld innerhalb eines Regelsatzes sind möglich. Es kann auch sinnvoll sein, bei PATTERN_SETS und PATTERNS nicht nur den jeweils ersten Match zu verwenden, sondern alle.

Man könnte natürlich noch viele Zusatzfunktionen ergänzen. Anhand problematischer Belege wird man erkennen, was da wirklich nützlich wäre. Deshalb würde ich am Anfang nicht übertreiben.



beta20 hat gesagt.:


> Eine weitere Frage noch:
> User1:
> - scannt Dokument ein
> - Lieferant gibt es noch nicht
> ...



Na ja, ich denke, das hängt schon von dem Zweck der Kategorie ab. Wenn das einfach eine Klassifizierung für den Lieferanten sein soll, muß man sich eben überlegen, ob man nur eine zulassen will oder mehrere und benötigt ein dazu passendes Datenmodell.
Wenn es darum geht, die Rechnung zu klassifizieren und das bei demselben Lieferanten mal so und mal anders sein kann, bietet sich evtl. an, auch das anhand von Mustern zu erkennen. Außerdem muß man sich überlegen, ob auch eine Rechnung zwei Kategorien angehören kann. Dann muß das Datenmodell das eben auch ermöglichen. Für die eigentliche Erkennung der Kategorien würde ich da keine allzu großen Schwierigkeiten erwarten.


----------



## beta20 (6. Dez 2018)

Vielen Dank für die klasse Beschreibung.

Also wenn ich das richtige verstehe, wäre deine "Pattern-Set" quasi dein "Lieferant".
Dies müsste aber auf jeden Fall noch mit dem Typ erweitert werden, sodass die Rechnung / Beleg automatisch einer Kategorie zugeordnet werden kann (Hotelkosten, Hostinggebühren...)

Vom Ablauf des Programms verstehe ich das dann so:
1) Rechnung wird eingelesen
2) OCR Text wird erstellt
3) OCR Text wird nach dem Regex von Tabelle PATTERN_SETS durchsucht.
   -> Wenn es ein Treffer gibt, dann werden alle Pattern aus der Tabelle PATTERNS angewendet um die benötigten Infos zu bekommen
4) Kann kein Pattern-Set angewendet werden, dann werden alle mögliche Pattern aus der Tabelle PATTERNS angewandt.
5) Mittels den gefunden Infos wie: Steuernummer / Name, wird dann ein neues PATTERN_SET erstellt

Meiner Meinung bräuchte man dann aber noch eine Zwischentabelle, die gleichen Patterns in der Tabelle PATTERN anzulegen, halte ich eher für unschön...???

PATTERN_SETS -> Die Lieferanten
PATTERNS -> mögliche Muser
PATTERN_SETS_PATTERN -> Zwischentabelle, sodass ein Lieferant mehrere PATTERNS nutzen kann
ID, PATTERN_SETS_FK, PATTERN_FK

Meines Erachtes müsste man die PATTERN - Tabelle auch noch um die Spalte "languageCode" erweitern.
Ein Lieferant (mit der gleichen Steuernummer) kann die Rechnung ja in Englisch, als auch in Deutsch ausliefern.
Durch eine Methode oder manuelle Auswahl des Users, wird dann eben der Sprachcode ermittelt.
Wenn die Rechnung in Englisch ist, dann werden eben PATTERN 1-2 angewandt, wenn in Deutsch, dann PATTERN 3-4. (PATTERN_SET_FK) ist jeweils der gleiche.


----------



## Xyz1 (6. Dez 2018)

Ihr schreibt soviel dass man gar nicht Lust hat das alles zu sehen. 

Rechnungsbetrag kann überall anders sein, aber ist meist der höchste Betrag, deswegen würd ich da dem Meniskusschaden zustimmen und es nicht mit machine learning machen.


----------



## Meniskusschaden (7. Dez 2018)

beta20 hat gesagt.:


> Also wenn ich das richtige verstehe, wäre deine "Pattern-Set" quasi dein "Lieferant".


Ja, nur eben universell und nicht auf Lieferanten beschränkt oder davon abhängig. Im Normalfall wird man für jeden Lieferanten genau ein Pattern-Set haben.


beta20 hat gesagt.:


> Dies müsste aber auf jeden Fall noch mit dem Typ erweitert werden, sodass die Rechnung / Beleg automatisch einer Kategorie zugeordnet werden kann (Hotelkosten, Hostinggebühren...)


Das kann ich noch nicht so richtig nachvollziehen. Ich hätte es wahrscheinlich eher über ein Pattern gelöst. Das würde evtl. noch eine einfache Ersetzungsfunktion erfordern (die aber ohnehin nützlich sein dürfte).


beta20 hat gesagt.:


> Vom Ablauf des Programms verstehe ich das dann so:
> 1) Rechnung wird eingelesen
> 2) OCR Text wird erstellt
> 3) OCR Text wird nach dem Regex von Tabelle PATTERN_SETS durchsucht.
> ...


Bis Punkt 3 stimme ich zu. Wenn es bis dahin keine Treffer gab, hat man eben nichts gefunden. Ich würde aber wahrscheinlich nicht nur das erste passende Pattern-Set ausführen, sondern alle passenden Sets. Die Punkte 4 und 5 würde ich weglassen.


beta20 hat gesagt.:


> Meiner Meinung bräuchte man dann aber noch eine Zwischentabelle, die gleichen Patterns in der Tabelle PATTERN anzulegen, halte ich eher für unschön...???


Wenn man Patterns mehrfach nutzt, kann das die Handhabung erschweren. Wenn die Erkennung bei einem Lieferanten mal nicht zufriedenstellend ist, wird man das entsprechende Pattern verbessern wollen. Falls das dann auch woanders genutzt wird, verschlechtert man möglicherweise das dort bisher gute Ergebnis. Also müsste man erst ein neues Pattern erstellen. Der Normalisierungsgedanke, der beim Datenbankentwurf sinnvoll ist, könnte hier eher stören.


beta20 hat gesagt.:


> PATTERN_SETS_PATTERN -> Zwischentabelle, sodass ein Lieferant mehrere PATTERNS nutzen kann


Das kann er doch ohnehin.


beta20 hat gesagt.:


> Meines Erachtes müsste man die PATTERN - Tabelle auch noch um die Spalte "languageCode" erweitern. Ein Lieferant (mit der gleichen Steuernummer) kann die Rechnung ja in Englisch, als auch in Deutsch ausliefern.


Ist das wirklich nötig? Einige rein strukturelle Pattern würden sprachunabhängig funktionieren. Und für die übrigen gestaltet man das Pattern entweder mehrsprachig oder legt pro Sprache ein eigenes an. Es matcht ja ohnehin nur auf sein Muster und muss gar nicht wissen, ob das dann deutsch oder englisch ist. Man kann für denselben Lieferanten auch zwei Pattern-Sets anlegen und in den Identifikations-RegEx eben noch ein geeignetes Wort der jeweiligen Sprache einbauen, so dass nur ein Set matcht. Oder man lässt einfach beide matchen und für manche Werte wird nur nur eines Ergebnisse liefern und für andere Werte tun es beide. Das schadet ja alles überhaupt nicht.


beta20 hat gesagt.:


> Durch eine Methode oder manuelle Auswahl des Users, wird dann eben der Sprachcode ermittelt.
> Wenn die Rechnung in Englisch ist, dann werden eben PATTERN 1-2 angewandt, wenn in Deutsch, dann PATTERN 3-4. (PATTERN_SET_FK) ist jeweils der gleiche.


Wie gesagt, sehe ich diese Notwendigkeit für die eigentliche Erkennung nicht, aber wenn man den Sprachcode für andere Zwecke dennoch benötigt, könnte man ihn auch über Pattern ermitteln lassen, sofern man die weiter oben erwähnte Ersetzungsfunktion einbaut. Das wäre ein Beispielfall dafür, nicht nur ein sondern alle Pattern-Sets ausführen zu lassen. Man definiert ein Pattern-Set, das auf jedes Dokument matcht und ein Pattern pro Sprache enthält, welches den Sprachcode liefert. Das individuelle Pattern-Set des Lieferanten matcht ebenfalls und liefert die übrigen Daten. So kann man ganz gut ein Baukastensystem aufbauen, bei dem global funktionierende Erkennungen nicht in jedes Pattern-Set integriert werden müssen.


----------



## Xyz1 (7. Dez 2018)

Was denn für PATTERN jetzt aufeinmal, wovon redet ihr, worum geht es?


----------



## beta20 (7. Dez 2018)

Ok, danke.

*Erkennung Typ der Rechnung (Kategorie):*
-> Wie willst du das über ein Pattern lösen?
-> Beispiel:
a) Du kaufst bei Amazon einen Stuhl und buchst das als Büromaterial
b) Morgen kaufst du bei Amazon einen Telefon und buchst das unter Telefon

-> Würdest du hier dann wiederum Patterns anlegen, damit die einzelnen Positionsarten ermittelt werden?


Hm, ich weiß nicht - halte ich eher für unschön, in der Tabelle PATTERNS mehrmals das gleiche Pattern zu speichern, wenn unterschiedliche Lieferanten das gleiche Pattern nutzen:

ID  PATTERN_SET    REGEX       
1   1                        (\b\w{24}\b)
2   2                        (\b\w{24}\b)

In der PATTERN - Tabelle würde ich wirklich nur die verfügbaren PATTERNS speichern, die es tatsächlich gibt, also genau 1x
Sofern kein Treffer eines PATTERN_SET gefunden wird, könnte ich ja die einzelnen PATTERN von der Tabelle PATTERN durchgehen, ggf. matched dann das ein oder andere aber eben nicht alle von einem PATTERN_SET

Ich kann ja über 1000 Lieferanten (also 1000 PATTERN_SETS) haben, wenn jeder von diesen mehrmals von der Syntax das gleiche PATTERN nutzt (also der Eintrag kommt mehrmals in der PATTERN Tabelle vor), ob das so sinnvoll ist?
Kann man mit Sicherheit so machen. Den Vorteil, den ich aber sehe ist, wenn ich keinen Treffer zu einem PATTERN_SET finde, muss ich nicht 1000 x X Patterns durchgehen, sondern nur die Einträge, die in PATTERN sind.


----------



## mihe7 (7. Dez 2018)

beta20 hat gesagt.:


> Sofern kein Treffer eines PATTERN_SET gefunden wird, könnte ich ja die einzelnen PATTERN von der Tabelle PATTERN durchgehen, ggf. matched dann das ein oder andere aber eben nicht alle von einem PATTERN_SET


SELECT DISTINCT `REGEX` FROM PATTERN;


----------



## Meniskusschaden (7. Dez 2018)

DerWissende hat gesagt.:


> Was denn für PATTERN jetzt aufeinmal, wovon redet ihr, worum geht es?


Im Kontext dieses Threads ist ein Pattern (ungefähr) ein regulärer Ausdruck, der den Zweck hat, den Wert für einen bestimmten Schlüssel (z.B. Rechnungsnummer) aus einer Rechnung eines bestimmten Lieferanten zu extrahieren. Und ein Pattern-Set ist eine Sammlung von Pattern, die die Werte für alle Schlüssel aus einer Rechnung eines bestimmten Lieferanten ermitteln sollen. Wenn man das wirklich programmiert, sollte man vielleicht bessere Namen finden.


beta20 hat gesagt.:


> *Erkennung Typ der Rechnung (Kategorie):*
> -> Wie willst du das über ein Pattern lösen?
> -> Beispiel:
> a) Du kaufst bei Amazon einen Stuhl und buchst das als Büromaterial
> ...


Ursprünglich war die Kategorie doch eher ein grobes Branchenkennzeichen, bei dem man davon ausgehen konnte, dass es bei demselben Lieferanten nahezu konstant ist (Hotel, Hoster). Da hätte man im Set des Lieferanten entweder ein Pattern mit einem konstanten Wert oder mehrere Pattern mit Bezeichnungen angelegt.
Das neue Beispiel (Stuhl, Telefon) ist jetzt aber viel spezifischer. Deine ursprüngliche Anforderung war kaum mehr, als den Rechnungsbetrag zu ermitteln, was man mal so eben aus der hohlen Hand umsetzen kann. Jetzt sind wir plötzlich bei einer Rechnungspositionserkennung. Ich hatte schon in einem meiner ersten Beiträge angedeutet, dass das eine ganz andere Grössenordnung ist. Das wird dann schon ein Projekt, bei dem man auch eine vernünftige Analyse machen muss. So etwas würde ich aber nur anfangen, wenn positionsweise Daten aus Bestellungen und Wareneingangen der Warenwirtschaft zur Verfügung stehen. Sonst kann man das, was man aus der Dokumentenerkennung bekommt, sowieso nicht sinnvoll weiter verarbeiten.


beta20 hat gesagt.:


> In der PATTERN - Tabelle würde ich wirklich nur die verfügbaren PATTERNS speichern, die es tatsächlich gibt, also genau 1x
> Sofern kein Treffer eines PATTERN_SET gefunden wird, könnte ich ja die einzelnen PATTERN von der Tabelle PATTERN durchgehen, ggf. matched dann das ein oder andere aber eben nicht alle von einem PATTERN_SET


Die würden bestimmt hier und da matchen. Wenn sie aber für einen anderen Lieferanten entwickelt wurden, bekommt man da aber sicher auch mal beispielsweise ein Auftragsdatum zurück, wenn man eigentlich ein Rechnungsdatum haben will. Die Lieferanten stimmen sich ja nicht untereinander ab, in welcher Reihenfolge sie solche Angaben auf der Rechnung machen.
Außerdem würden wahrscheinlich Pattern-Leichen entstehen, weil man bei Anpassungen sicherheitshalber ein neues Pattern erstellt, obwohl es vielleicht ausschließlich für den Lieferanten, den man gerade verbessern will, benutzt wird und gefahrlos geändert werden könnte. Ich glaube, es ist viel einfacher, bei einem neuen Lieferanten irgendein Pattern-Set zu kopieren und da die RegEx rein zu kopieren, die man im RegExp-Tester entwickelt.
Die Variationen der OCR können so vielfältig sein, dass es ohnehin schwierig wäre, vordefinierte Pattern vernünfttig zu benennen, damit man sie für eine Wiederverwendung überhaupt findet. Man braucht unterschiedliche Pattern ja nicht nur aufgrund verschieden strukturierter Rechnungen, sondern auch zur Kompensation von OCR-Fehlern. Da muß man manchmal trotz eigentlich gleicher Struktur dennoch individuelle Umwege nehmen.


beta20 hat gesagt.:


> Den Vorteil, den ich aber sehe ist, wenn ich keinen Treffer zu einem PATTERN_SET finde, muss ich nicht 1000 x X Patterns durchgehen, sondern nur die Einträge, die in PATTERN sind.


Wie bereits im vorigen Abschnitt beschrieben, würde ich das nicht machen, denn ich hätte lieber keinen Treffer, als einen falschen.


----------



## X2X (24. Jan 2020)

Hallo Beta20,
Bist Du in der Zwischenzeit zu einer Lösung gekommen?


----------



## beta20 (24. Jan 2020)

leider nein


----------



## X2X (24. Jan 2020)

Wir verwenden dazu den X2X-Software-Roboter von triple-s (www.sss.de).

Das grundsätzliche Vergehen ist genau wie hier diskutiert. Es gibt eine Datei in der zu jedem Lieferanten Erkennungsmerkmale wie zum Beispiel die Umsatzsteuernummer hinterlegt sind. Der Software-Roboter entscheidet damit welches Rechnungstemplate (Stucture-TYPE) verwendet werden soll. In zweiten Schritt wir das Template verwendet um alle Daten aus der Rechnung auszulesen.

Das Rechnungstemplate (TYPE) legt der Anwender mit einer speziellen aber einfachen Hochsprache fest. (Hat nichts mit RegExp zu tun). Der Clou ist jetzt noch, dass der Anwender auch noch selbst festlegen kann, in welchem Format er die gelesen Daten zur Weiterverarbeitung ablegen will. Das kann ein Standardformat wie Json oder XML sein oder aber auch ein ganz individuelles Hausformat. Dafür stehen andere Templates (sogenannte PATTERN) zu Verfügung.

Es ist natürlich klar, dass da aus den TYPEs zur Laufzeit irgendwie ein Parser und aus den Pattern zu Laufzeit irgendwie ein Generator gebaut wird.


----------



## beta20 (24. Jan 2020)

also ich hatte mich damit weiterbefasst und bin dann irgendwann zu Machine Learning gekommen.
Sprich es kommen immer wieder neue Rechnungsformate dazu, sodass das System dazu lernen muss.

Weiter habe ich es dann aber nicht verfolgt, da es nicht Prio1 ist. Aber wenn in naher Zukunft benötige ich es...


----------



## TM69 (24. Jan 2020)

beta20 hat gesagt.:


> Ok, danke.
> 
> Ich brauche den Scan nicht als Word / Excelfile.
> Ich will lediglich aus dem Scan / Datei die verschiedenen Informationen aus einer Rechnung herausbekommen (Betrag, Datum...).
> ...


Es lohnt sich nicht. Denn echte Bürokopierer / Scanner machen dieses von Hause. Allerdings sei hier vorsichtig, wie folgender Beitrag zeigt:





Ansonsten gibt es einige OCR SDK sowohl OpenSource als auch ClosedSource z.B. Abby
https://www.abbyy.com/de-de/ocr-sdk/?gclid=EAIaIQobChMIod3DqtKc5wIVxOJ3Ch1G9wuTEAAYASAAEgJ_IPD_BwE


----------



## X2X (24. Jan 2020)

beta20 hat gesagt.:


> also ich hatte mich damit weiterbefasst und bin dann irgendwann zu Machine Learning gekommen.
> Sprich es kommen immer wieder neue Rechnungsformate dazu, sodass das System dazu lernen muss.
> 
> Weiter habe ich es dann aber nicht verfolgt, da es nicht Prio1 ist. Aber wenn in naher Zukunft benötige ich es...


Wenn man die Sammlung der Templates als das Wissen des Software-Roboters betrachtet, dann ist es Machine-Learning, weil ja immer wieder neue Lieferanten/Templates dazukommen oder auch mal erweitert werden müssen.


----------



## Meniskusschaden (24. Jan 2020)

TM69 hat gesagt.:


> Es lohnt sich nicht. Denn echte Bürokopierer / Scanner machen dieses von Hause.


Also man legt ein Dokument in den Scanner und der gibt dann nur mit Bordmitteln strukturiert Lieferantennamen, Rechnungsnummer, Rechnungsdatum, Rechnungsbetrag etc. zurück? So ein Gerät hätte ich gerne. Wo gibt's die denn?


----------



## TM69 (24. Jan 2020)

Meniskusschaden hat gesagt.:


> Also man legt ein Dokument in den Scanner und der gibt dann nur mit Bordmitteln strukturiert Lieferantennamen, Rechnungsnummer, Rechnungsdatum, Rechnungsbetrag etc. zurück? So ein Gerät hätte ich gerne. Wo gibt's die denn?


Okay sry falsch ausgedrückt, ich wollte damit sagen das professionelle Geräte SDKs bieten. Standisierte Formular können z.B. durch DMS mit OCR erreichen, soweit mir bekannt kann dieses z.B. Alfresco.


----------



## beta20 (24. Jan 2020)

Im Prinzip möchte ich sowas erreichen:








						„Die Lernkurve für klassische Entwickler ist bei KI-Themen deutlich höher als bei einer neuen Programmiersprache“
					

Wie geht man dabei vor, künstliche Intelligenz im Unternehmen einzubinden? Wir haben mit Fabian Silberer, Gründer von sevDesk, gesprochen.




					entwickler.de


----------



## beta20 (19. Nov 2018)

Hallo zusammen, 

ich würde gerne eine automatische Rechnungserkennung programmieren.
Ich frage mich jedoch gerade wie das technisch genau abläuft, wie erkennt mein OCR den Rechnungsbetrag, Datum etc.?

Hier meine Idee...
1) Ich scanne ein PDF / Image ein
2) Jage das über den OCR (z.B. Tessa4j OCR).
3) Nun erhalte ich einen String zurück
4) Ich prüfe den String nun auf verschiedene String ab (z.B. "Rechnungsdatum", "Rechnungsbetrag"; dahinter sollte dann i.d.R. der Rechnungsbetrag etc. stehen...
5) Wie erhalte ich den Betrag / Datum aber nun?

Danke für jede Hilfe.


----------



## Meniskusschaden (24. Jan 2020)

TM69 hat gesagt.:


> z.B. durch DMS mit OCR erreichen, soweit mir bekannt kann dieses z.B. Alfresco.


Alfresco hatte ich mir zwar vor vielen Jahren mal flüchtig angesehen, kenne es aber im Grunde nur dem Namen nach. Aber egal welches DMS man nutzt: entweder muß man eine KI trainieren oder ein Regelwerk aufbauen. Beides wird im Laufe der Jahre immer weiter verbessert und stellt dann einen eigenen Wert dar. Deshalb sollte man sich überlegen, ob man den Klassifizierungsprozess überhaupt mit DMS-Funktionalität realisieren möchte oder doch lieber an eine unabhängige Lösung auslagert (erst mal egal, ob Eigenprogrammierung oder eine Lösung, wie sie @X2X offenbar anbietet). Wenn man das DMS dann mal wechseln möchte, kann man den bestehenden Klassifizierungsprozess behalten und muss an der Stelle keinen großen Migrationsaufwand betreiben.


----------



## mihe7 (24. Jan 2020)

X2X hat gesagt.:


> Wenn man die Sammlung der Templates als das Wissen des Software-Roboters betrachtet, dann ist es Machine-Learning, weil ja immer wieder neue Lieferanten/Templates dazukommen oder auch mal erweitert werden müssen.


Äh... damit ich es richtig verstehe: wenn ich ein Template erweitere, dann ist es Machine-Learning, weil ich der Maschine was lerne?


----------



## Thallius (25. Jan 2020)

mihe7 hat gesagt.:


> Äh... damit ich es richtig verstehe: wenn ich ein Template erweitere, dann ist es Machine-Learning, weil ich der Maschine was lerne?



Naja du bringst der Maschine was bei. Ergo lernt sie etwas


----------



## haste.makes.waste (31. Mrz 2022)

Mit denen hab ich so was auch schon gemacht: 








						KI: Vom Prototyp zum Produkt - BLU DELTA - Belegerfassung automatisieren
					

Einblicke in die Erfolgsfaktoren der Entwicklung einer Künstlichen Intelligenz für die Automatisierung der Dokumentenerfassung.




					www.bludelta.de


----------



## haste.makes.waste (31. Mrz 2022)

Hab es mit dem implementiert - hier gibts Java Sample Client in GitHub https://github.com/blumatix
bzw. hier https://www.bludelta.de/de/get-started/


----------



## internet (4. Apr 2022)

Ich suche auch gerade sowas...
Was kostet denn die "OCR OnPremise-SDK" ?


----------



## KonradN (4. Apr 2022)

internet hat gesagt.:


> Ich suche auch gerade sowas...
> Was kostet denn die "OCR OnPremise-SDK" ?


Von was redest Du genau? Meinst Du Googles OCR On-Prem Lösung wie unter https://cloud.google.com/vision/on-prem beschrieben oder meinst Du etwas anders?

Bei Google On-Prem brauchst Du einen GKE oder Anthos Cluster - da wäre evtl. erst einmal die Frage, ob sowas vorhanden ist... und wenn, dann könnte man das da mit den Verantwortlichen abklären denke ich mal


----------



## internet (4. Apr 2022)

wie oben gepostet: 








						BLU DELTA - Next Generation Invoice Capturing
					

Selbstlernend - Preiswert - Sicher. Durch Machine Learning erzielt unser System Erkennungsraten von 94,5%.




					www.bludelta.de


----------



## KonradN (4. Apr 2022)

internet hat gesagt.:


> wie oben gepostet:
> 
> 
> 
> ...


Ach so, das nennt sich auch so - das hatte ich nicht gesehen. Sorry.


----------



## Kanadier (20. Apr 2022)

Kanadier hier,

ich habe euch ueber Google gefunden, nachdem ich neugierig war, wie deutsche Firmen das handhaben.
Wir arbeiten an demselben Problem in eine der groessten Steuerfirmen unseres Landes in Kanada.

Lass uns ueber die Extrahierung von Key-Value Paaren reden (Tabellen sind eine Sache fuer sich).

Ich habe lange ueber dieses Problem nachgedacht, und bin schliesslich auf die fuer mich "weiseste" Loesung gekommen, die "gut genug" zu sein scheint, eine simple Loesung zu einem sehr komplizierten Thema. (Ich habe spaeter auch herausgefunden, dass Google einen aehnlichen Ansatz mit ihrem System verfolgt, das hier schon empfohlen wurde. Nein, nicht nur im aehnlichen Ansatz... die machen es haargenauso)

Du erstellst dir zuerst "Kandidaten", das sind Tokens, also "Woerter" die von ihrer Zusammensetzung aus Buchstaben ein moeglicher Match sein koennen.
Danach schaust du dir die Nachbarn von jedem Kandidaten "nach links" an und wenn du nicht fuendig wirst um 10% "nach oben" (behalte beim OCR-Prozess also die x-y Koordinaten, die sind wichtig)

Der "weise" Teil ist ein Verifizierungsprozess, um "Fehltreffer" auszuwerfen. Du kannst schon von vornherein einige Heuristiken aufstellen:
Die Gesamtsumme ist der hoechste Geldbetrag.
Mehrwertsteuer ist bei euch ~19% von der Gesamtsumme; neben der Gesamtsumme wuerde nicht ein anderes Keyword (z.B. "Rueckgeld") stehen.
Das Zahldatum kommt nach dem Rechnungsdatum etc. etc.

Es gibt knapp ueber 500 Keywords in Rechnungen bei uns, nach denen wir suchen. Alles KI ist nur "Kurvenanpassung."

Ich habe meiner Assitentin gesagt, 80% Treffsicherheit ist top. 90% Erfolgsrate ist 5 Jahre Entwicklungszeit und um von 90% auf 95% zu kommen sind nochmal 10 Jahre. Ich denke, jeder der aus diesem Bereich kommt, wird bestaetigen: Bei 95% flacht auch dann diese Kurve ab.

So gut wie alle Forschungspapiere ueber dieses Thema gelesen zu haben gebietet mir diesen Loesungsweg zu favoritisieren (obgleich ich auch widersprochen werden moechte). TensorFlow, um auf Fabian von dem Link zu entwickler.de einzugehen, ist eine gute Idee, bis du skalieren musst. Daniel Holanda Noronha hat mit LeFlow versucht TensorFlow auf FPGAs zu werfen. FPGAs sind eine gute Idee.

Wir brauchen definitiv mehr FPGA-OCR Forschungen. Ich habe auch einige Ideen zum Thema OCR, aber ich moechte damit nicht mein Leben verschwenden.

"Wahre Semantik" in Rechnungen reinzubringen... dazu muesstest du vorerst ein System wie Cyc haben, das ueber die "groessere Welt" bescheid weiss. Der Kerninterpreter von CYC ist im Wesentlichen wie ein metazirkulaerer Lisp Interpreter. Die Inferenzregeln koennen etwa zwei Dutzend sein und sind im Wesentlichen Einzeiler im Pradikatenkalkuel 2. Ordnung. Der Rest von CYC besteht im Wesentlichen aus verschiedenen Arten von Wissen, die als Beziehungen und Kausalketten kodiert sind.

Die Inferenzmaschine ist pille-palle, wenn man die praktische Vergroesserung dieser Regeln zur Optimierung ignoriert. Die Einstein-Frage lautet, "Was genau muss es wissen - und wie viel, um das ganze praktisch zu machen?"


----------

