Converti testo non strutturato sottoposto a OCR in testo corretto
-
21-12-2019 - |
Domanda
Sto usando Microsoft MODI
In VB6
per eseguire l'OCR di un'immagine.(Conosco altri strumenti OCR come tesseract ecc. Ma trovo MODI più accurato di altri)
L'immagine da sottoporre a OCR è così
e il testo che ottengo dopo l'OCR è come sotto
Text1
Text2
Text3
Number1
Number2
Number3
Il problema qui è che il testo corrispondente della colonna opposta non viene mantenuto.Come posso mappare Number1 con Text1?
Posso solo pensare ad una soluzione come questa.
MODI fornisce le coordinate di tutte le parole OCR come questa
LeftPos = Img.Layout.Words(0).Rects(0).Left
TopPos = Img.Layout.Words(0).Rects(0).Top
Quindi, per allineare le parole sulla stessa riga, possiamo abbinare la TopPos di ciascuna parola e quindi ordinarle in base alla LeftPos.Otterremo la linea completa.Quindi ho eseguito il loop di tutte le parole e ho memorizzato il loro testo, nonché sinistra e parte superiore in una tabella mysql.quindi ha eseguito questa query
SELECT group_concat(word ORDER BY `left` SEPARATOR ' ')
FROM test_copy
GROUP BY `top`
Il mio problema è che le posizioni in alto non sono esattamente le stesse per ogni parola, ovviamente ci saranno un paio di differenze di pixel.
Ho provato ad aggiungere DIV 5
, per unire parole che si trovano nell'intervallo di 5 pixel ma che in alcuni casi non funziona.Ho anche provato a farlo in node.js calcolando la tolleranza per ogni parola e quindi ordinando per LeftPos, ma sento ancora che questo non è il modo migliore per farlo.
Aggiornamento: Il codice js fa il lavoro, ma ad eccezione del caso in cui Number1 ha una differenza di 5 pixel e Text2 non ha corrispondenti in quella riga.
C'è qualche idea migliore per farlo?
Soluzione
Non sono sicuro al 100% di come identifichi quelle parole che si trovano nella colonna "sinistra", ma una volta identificata quella parola puoi trovare altre parole nella riga proiettando non solo la coordinata Superiore ma l'intero rettangolo attraverso ( sia in alto che in basso).Determina la sovrapposizione (intersezione) con le altre parole.Notare l'area contrassegnata in rosso di seguito.
Questa è la tolleranza che puoi utilizzare per rilevare se qualcosa è nella stessa linea.Se qualcosa si sovrappone solo di un pixel, probabilmente proviene da una linea inferiore o superiore.Ma se si sovrappone, diciamo, del 50% o più dell'altezza "Testo1", è probabile che sia sulla stessa riga.
Esempio SQL per trovare tutte le parole nella "riga" in base alla coordinazione superiore e inferiore
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)
Esempio di pseudo codice VB6 per calcolare anche le linee.
'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.