Konvertieren Sie mit OCR bearbeiteten unstrukturierten Text in richtigen Text
-
21-12-2019 - |
Frage
Ich verwende Microsoft MODI
In VB6
um ein Bild zu OCR zu machen.(Ich kenne andere OCR-Tools wie Tesseract usw., aber ich finde MODI genauer als andere)
Das Bild, das mit OCR bearbeitet werden soll, sieht folgendermaßen aus
und der Text, den ich nach der OCR erhalte, ist wie folgt
Text1
Text2
Text3
Number1
Number2
Number3
Das Problem hierbei ist, dass der entsprechende Text aus der gegenüberliegenden Spalte nicht beibehalten wird.Wie kann ich Number1 mit Text1 zuordnen?
Ich kann mir nur eine solche Lösung vorstellen.
MODI stellt die Koordinaten aller OCR-Wörter wie dieses bereit
LeftPos = Img.Layout.Words(0).Rects(0).Left
TopPos = Img.Layout.Words(0).Rects(0).Top
Um Wörter in derselben Zeile auszurichten, können wir die TopPos jedes Wortes abgleichen und sie dann nach LeftPos sortieren.Wir bekommen die komplette Linie.Also habe ich alle Wörter durchlaufen und ihren Text sowie links und oben in einer MySQL-Tabelle gespeichert.Dann habe ich diese Abfrage ausgeführt
SELECT group_concat(word ORDER BY `left` SEPARATOR ' ')
FROM test_copy
GROUP BY `top`
Mein Problem ist, dass die Spitzenpositionen nicht für jedes Wort genau gleich sind. Offensichtlich wird es einige Pixelunterschiede geben.
Ich habe versucht, hinzuzufügen DIV 5
, zum Zusammenführen von Wörtern im 5-Pixel-Bereich, aber das funktioniert in einigen Fällen nicht.Ich habe es auch in node.js versucht, indem ich die Toleranz für jedes Wort berechnet und dann nach LeftPos sortiert habe, aber ich habe immer noch das Gefühl, dass dies nicht der beste Weg ist.
Aktualisieren: Der js-Code erledigt den Job, außer in dem Fall, dass Nummer1 einen Unterschied von 5 Pixeln hat und Text2 in dieser Zeile keine Entsprechung hat.
Gibt es eine bessere Idee, dies zu tun?
Lösung
Ich bin mir nicht 100 % sicher, wie Sie die Wörter identifizieren, die sich in Ihrer „linken“ Spalte befinden, aber sobald Sie dieses Wort identifiziert haben, können Sie andere Wörter in der Zeile finden, indem Sie nicht nur die obere Koordinate, sondern das gesamte Rechteck über ( sowohl oben als auch unten).Bestimmen Sie die Überschneidung (Schnittpunkt) mit den anderen Wörtern.Beachten Sie den unten rot markierten Bereich.
Dies ist die Toleranz, mit der Sie erkennen können, ob sich etwas in derselben Zeile befindet.Wenn sich etwas nur um ein Pixel überlappt, stammt es wahrscheinlich aus einer niedrigeren oder höheren Zeile.Wenn es sich jedoch beispielsweise um 50 % oder mehr der Höhe „Text1“ überlappt, befindet es sich wahrscheinlich in derselben Zeile.
Beispiel-SQL, um alle Wörter in der „Zeile“ basierend auf der oberen und unteren Koordinate zu finden
select
word.id, word.Top, word.Left, word.Right, word.Bottom
from
word
where
(word.Top >= @leftColWordTop and word.Top <= @leftColWordBottom)
or (word.Bottom >= @leftColWordTop and word.Bottom <= @leftColWordBottom)
Beispiel für Pseudo-VB6-Code zur Berechnung der Zeilen.
'assume words is a collection of WordInfo objects with an Id, Top,
' Left, Bottom, Right properties filled in, and a LineAnchorWordId
' property that has not been set yet.
'get the words in left-to-right order
wordsLeftToRight = SortLeftToRight(words)
'also get the words in top-to-bottom order
wordsTopToBottom = SortTopToBottom(words)
'pass through identifying a line "anchor", that being the left-most
' word that starts (and defines) a line
for each anchorWord in wordsLeftToRight
'check if the word has been mapped to aline yet by checking if
' its anchor property has been set yet. This assumes 0 is not
' a valid id, use -1 instead if needed
if anchorWord.LineAnchorWordId = 0 then
'not locate every word on this line, as bounded by the
' anchorWord. every word determined to be on this line
' gets its LineAnchorWordId property set to the Id of the
' anchorWord
for each lineWord in wordsTopToBottom
if lineWord.Bottom < anchorWord.Top Then
'skip it,it is above the line (but keep searching down
' because we haven't reached the anchorWord location yet)
else if lineWord.Top > anchorWord.Bottom Then
'skip it,it is below the line, and exit the search
' early since all the rest will also be below the line
exit for
else if OverlapsWithinTolerance(anchorWord, lineWord) then
lineWord.LineAnchorWordId = anchorWord.Id
endif
next
end if
next anchorWord
'at this point, every word has been assigned a LineAnchorWordId,
' and every word on the same line will have a matching LineAnchorWordId
' value. If stored in a DB you can now group them by LineAnchorWordId
' and sort them by their Left coord to get your output.