Convierta texto no estructurado con OCR en texto adecuado
-
21-12-2019 - |
Pregunta
estoy usando microsoft MODI
en VB6
para OCR una imagen.(Conozco otras herramientas de OCR como tesseract, etc., pero encuentro que MODI es más preciso que otras)
La imagen a OCRed es así
y el texto que recibo después del OCR es el siguiente
Text1
Text2
Text3
Number1
Number2
Number3
El problema aquí es que no se mantiene el texto correspondiente de la columna opuesta.¿Cómo puedo asignar Número1 con Texto1?
Sólo puedo pensar en una solución como esta.
MODI proporciona coordenadas de todas las palabras OCR como esta
LeftPos = Img.Layout.Words(0).Rects(0).Left
TopPos = Img.Layout.Words(0).Rects(0).Top
Entonces, para alinear palabras en la misma línea, podemos hacer coincidir TopPos de cada palabra y luego ordenarlas por LeftPos.Obtendremos la línea completa.Así que recorrí todas las palabras y almacené su texto, así como el izquierdo y el superior en una tabla MySQL.luego ejecuté esta consulta
SELECT group_concat(word ORDER BY `left` SEPARATOR ' ')
FROM test_copy
GROUP BY `top`
Mi problema es que las posiciones superiores no son exactamente las mismas para cada palabra. Obviamente, habrá un par de diferencias de píxeles.
Intenté agregar DIV 5
, para fusionar palabras que están en un rango de 5 píxeles, pero eso no funciona en algunos casos.También intenté hacerlo en node.js calculando la tolerancia para cada palabra y luego ordenándola por LeftPos, pero sigo sintiendo que esta no es la mejor manera de hacerlo.
Actualizar: El código js hace el trabajo, excepto en el caso en que Número1 tiene una diferencia de 5 píxeles y Texto2 no tiene correspondencia en esa línea.
¿Hay alguna idea mejor para hacer esto?
Solución
No estoy 100% seguro de cómo identifica esas palabras que están en su columna "izquierda", pero una vez que tenga esa palabra identificada, puede encontrar otras palabras en la línea de TI al proyectar no solo la coordenada superior, sino la totalidad.Rectángulo a través (tanto arriba como inferior).Determine la superposición (intersección) con las otras palabras.Tenga en cuenta el área marcada en rojo debajo.
Esta es la tolerancia que puede usar para detectar si algo está en la misma línea.Si algo se superpone solo con un píxel, es probable que sea de una línea inferior o superior.Pero si se superpone, digamos, 50% o más de la altura "Text1, entonces es probable en la misma línea.
Ejemplo SQL para encontrar todas las palabras en la "línea" basada en la ATOP y la coorda inferior
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)
Ejemplo de código PSUEDO VB6 para calcular las líneas también.
'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.