ocr-stream 1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ocr-stream might be problematic. Click here for more details.
- ocr_stream/__init__.py +10 -0
- ocr_stream/__main__.py +43 -0
- ocr_stream/_version.py +5 -0
- ocr_stream/extractors.py +108 -0
- ocr_stream/models/__init__.py +3 -0
- ocr_stream/models/m_extractors.py +39 -0
- ocr_stream/models/m_modules_ocr.py +78 -0
- ocr_stream/modules_ocr.py +429 -0
- ocr_stream/utils/__init__.py +13 -0
- ocr_stream-1.1.dist-info/METADATA +57 -0
- ocr_stream-1.1.dist-info/RECORD +13 -0
- ocr_stream-1.1.dist-info/WHEEL +5 -0
- ocr_stream-1.1.dist-info/top_level.txt +1 -0
ocr_stream/__init__.py
ADDED
ocr_stream/__main__.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
------------------------------------------------------------
|
|
5
|
+
Configuração instalação:
|
|
6
|
+
------------------------------------------------------------
|
|
7
|
+
$ pip3 install -r requirements.txt
|
|
8
|
+
$ pip3 install https://gitlab.com/bschaves/pdflib/-/archive/V1.0/pdflib-V1.0.zip
|
|
9
|
+
|
|
10
|
+
------------------------------------------------------------
|
|
11
|
+
Referências:
|
|
12
|
+
------------------------------------------------------------
|
|
13
|
+
|
|
14
|
+
https://gist.github.com/endolith/334196bac1cac45a4893
|
|
15
|
+
|
|
16
|
+
Tesseract OCR
|
|
17
|
+
https://github.com/tesseract-ocr/tesseract
|
|
18
|
+
|
|
19
|
+
pytesseract
|
|
20
|
+
https://github.com/h/pytesseract
|
|
21
|
+
|
|
22
|
+
pyocr
|
|
23
|
+
https://gitlab.gnome.org/World/OpenPaperwork/pyocr
|
|
24
|
+
"""
|
|
25
|
+
import sys, os
|
|
26
|
+
this_file = os.path.abspath(os.path.relpath(__file__))
|
|
27
|
+
dir_of_project = os.path.dirname(this_file)
|
|
28
|
+
sys.path.insert(0, dir_of_project)
|
|
29
|
+
|
|
30
|
+
from convert_stream import print_title
|
|
31
|
+
from ocr_stream import __version__, __modify_data__
|
|
32
|
+
|
|
33
|
+
def test():
|
|
34
|
+
# /usr/bin/tesseract
|
|
35
|
+
# /usr/share/tesseract-ocr/5/tessdata
|
|
36
|
+
pass
|
|
37
|
+
|
|
38
|
+
def main():
|
|
39
|
+
print_title(f' ocrlib Versão: {__version__} | Atualização: {__modify_data__} ')
|
|
40
|
+
test()
|
|
41
|
+
|
|
42
|
+
if __name__ == '__main__':
|
|
43
|
+
main()
|
ocr_stream/_version.py
ADDED
ocr_stream/extractors.py
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from ocr_stream.utils import (
|
|
5
|
+
File,
|
|
6
|
+
Directory,
|
|
7
|
+
ImageObject,
|
|
8
|
+
DataFrame,
|
|
9
|
+
PageDocumentPdf,
|
|
10
|
+
DocumentPdf,
|
|
11
|
+
PdfStream,
|
|
12
|
+
LibraryPDF,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
from ocr_stream.models import (
|
|
16
|
+
ABCRecognizeImage,
|
|
17
|
+
LibraryOCR,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from ocr_stream.modules_ocr import ModuleOcr, TextRecognized
|
|
21
|
+
|
|
22
|
+
class RecognizeImage(ABCRecognizeImage):
|
|
23
|
+
def __init__(self, module_ocr):
|
|
24
|
+
super().__init__(module_ocr)
|
|
25
|
+
|
|
26
|
+
def image_content_data(self, img: ImageObject | File) -> DataFrame:
|
|
27
|
+
if isinstance(img, File):
|
|
28
|
+
return self.module_ocr.image_content_data(ImageObject.create_from_file(img))
|
|
29
|
+
elif isinstance(img, ImageObject):
|
|
30
|
+
return self.module_ocr.image_content_data(img)
|
|
31
|
+
else:
|
|
32
|
+
raise ValueError(f'{__class__.__name__}\nUse: ImageObject() ou File(), não {type(img)}')
|
|
33
|
+
|
|
34
|
+
def image_recognize(self, img: ImageObject | File) -> TextRecognized:
|
|
35
|
+
if isinstance(img, File):
|
|
36
|
+
return self.module_ocr.image_recognize(ImageObject.create_from_file(img))
|
|
37
|
+
elif isinstance(img, ImageObject):
|
|
38
|
+
return self.module_ocr.image_recognize(img)
|
|
39
|
+
else:
|
|
40
|
+
raise ValueError(f'{__class__.__name__}\nUse: ImageObject() ou File(), não {type(img)}')
|
|
41
|
+
|
|
42
|
+
def image_to_string(self, img: ImageObject | File) -> str:
|
|
43
|
+
if isinstance(img, File):
|
|
44
|
+
return self.module_ocr.imag_to_string(ImageObject.create_from_file(img))
|
|
45
|
+
elif isinstance(img, ImageObject):
|
|
46
|
+
return self.module_ocr.imag_to_string(img)
|
|
47
|
+
else:
|
|
48
|
+
raise ValueError(f'{__class__.__name__}\nUse: ImageObject() ou File(), não {type(img)}')
|
|
49
|
+
|
|
50
|
+
@classmethod
|
|
51
|
+
def create(cls, library_ocr=LibraryOCR.PYTESSERACT, *, path_tesseract, lang=None, tess_data_dir=None) -> RecognizeImage:
|
|
52
|
+
module_ocr:ModuleOcr = ModuleOcr.create(
|
|
53
|
+
library_ocr,
|
|
54
|
+
path_tesseract=path_tesseract,
|
|
55
|
+
lang=lang,
|
|
56
|
+
tess_data_dir=tess_data_dir
|
|
57
|
+
)
|
|
58
|
+
return cls(module_ocr)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class RecognizePdf(object):
|
|
62
|
+
def __init__(self, recognize_image:RecognizeImage):
|
|
63
|
+
self.recognize_image:RecognizeImage = recognize_image
|
|
64
|
+
|
|
65
|
+
def recognize_page_pdf(self, page:PageDocumentPdf) -> PageDocumentPdf:
|
|
66
|
+
"""
|
|
67
|
+
Converte a página em Imagem, reconhece o texto com OCR e
|
|
68
|
+
retorna uma nova página com o texto reconhecido.
|
|
69
|
+
"""
|
|
70
|
+
pdf_stream = PdfStream(library_pdf=LibraryPDF.FITZ)
|
|
71
|
+
pdf_stream.add_page(page)
|
|
72
|
+
img:ImageObject = pdf_stream.to_images()[0]
|
|
73
|
+
text_recognized:TextRecognized = self.recognize_image.image_recognize(img)
|
|
74
|
+
return text_recognized.to_page_pdf()
|
|
75
|
+
|
|
76
|
+
def recognize_document(self, doc:DocumentPdf) -> DocumentPdf:
|
|
77
|
+
new:DocumentPdf = DocumentPdf()
|
|
78
|
+
for page in doc.pages:
|
|
79
|
+
recognized_page:PageDocumentPdf = self.recognize_page_pdf(page)
|
|
80
|
+
new.add_page(recognized_page)
|
|
81
|
+
return new
|
|
82
|
+
|
|
83
|
+
@classmethod
|
|
84
|
+
def create(
|
|
85
|
+
cls,
|
|
86
|
+
library_ocr=LibraryOCR.PYTESSERACT,
|
|
87
|
+
*,
|
|
88
|
+
path_tesseract:File,
|
|
89
|
+
lang:str=None,
|
|
90
|
+
tess_data_dir:Directory=None,
|
|
91
|
+
) -> RecognizePdf:
|
|
92
|
+
##
|
|
93
|
+
recognize_image = RecognizeImage.create(
|
|
94
|
+
library_ocr,
|
|
95
|
+
path_tesseract=path_tesseract,
|
|
96
|
+
lang=lang,
|
|
97
|
+
tess_data_dir=tess_data_dir
|
|
98
|
+
)
|
|
99
|
+
return cls(recognize_image)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
#
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from abc import ABC, abstractmethod
|
|
5
|
+
|
|
6
|
+
from pandas import DataFrame
|
|
7
|
+
from soup_files import File, Directory
|
|
8
|
+
from convert_stream import ImageObject
|
|
9
|
+
from ocr_stream.models.m_modules_ocr import ABCModuleOcr, ABCTextRecognized, LibraryOCR
|
|
10
|
+
|
|
11
|
+
class ABCRecognizeImage(ABC):
|
|
12
|
+
def __init__(self, module_ocr:ABCModuleOcr):
|
|
13
|
+
super().__init__()
|
|
14
|
+
self.module_ocr:ABCModuleOcr = module_ocr
|
|
15
|
+
|
|
16
|
+
@abstractmethod
|
|
17
|
+
def image_to_string(self, img:ImageObject | File) -> str:
|
|
18
|
+
pass
|
|
19
|
+
|
|
20
|
+
@abstractmethod
|
|
21
|
+
def image_recognize(self, img:ImageObject | File) -> ABCTextRecognized:
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
@abstractmethod
|
|
25
|
+
def image_content_data(self, img:ImageObject | File) -> DataFrame:
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
@classmethod
|
|
29
|
+
def create(
|
|
30
|
+
cls,
|
|
31
|
+
library_ocr:LibraryOCR = LibraryOCR.PYTESSERACT,
|
|
32
|
+
*,
|
|
33
|
+
path_tesseract:File,
|
|
34
|
+
lang:str=None,
|
|
35
|
+
tess_data_dir:Directory=None
|
|
36
|
+
) -> ABCRecognizeImage:
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
#
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
from typing import Dict, List
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from pandas import DataFrame
|
|
8
|
+
from soup_files import File, Directory
|
|
9
|
+
from convert_stream import ImageObject, DocumentPdf, PageDocumentPdf, LibraryImage
|
|
10
|
+
|
|
11
|
+
class LibraryOCR(Enum):
|
|
12
|
+
PYTESSERACT = 'pytesseract'
|
|
13
|
+
PYOCR = 'pyocr'
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ABCTextRecognized(ABC):
|
|
17
|
+
def __init__(self, bytes_recognized:bytes):
|
|
18
|
+
super().__init__()
|
|
19
|
+
self.bytes_recognized:bytes = bytes_recognized
|
|
20
|
+
|
|
21
|
+
@abstractmethod
|
|
22
|
+
def to_string(self) -> str:
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
@abstractmethod
|
|
26
|
+
def to_page_pdf(self) -> PageDocumentPdf:
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
@abstractmethod
|
|
30
|
+
def to_document(self) -> DocumentPdf:
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
@abstractmethod
|
|
34
|
+
def to_dataframe(self, column:str='TEXT') -> DataFrame:
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
@abstractmethod
|
|
38
|
+
def to_dict(self) -> Dict[str, List[str]]:
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
#======================================================================#
|
|
42
|
+
# Abstração para o módulo que extrai o texto das imagens (OCR)
|
|
43
|
+
# pode ser implementado com pytesseract ou outros.
|
|
44
|
+
#======================================================================#
|
|
45
|
+
class ABCModuleOcr(ABC):
|
|
46
|
+
def __init__(self, *, cmd_executable:File, lang:str=None, tess_data_dir:Directory=None):
|
|
47
|
+
self.cmd_executable:File = cmd_executable
|
|
48
|
+
self.lang:str = lang
|
|
49
|
+
self.tess_data_dir:Directory = tess_data_dir
|
|
50
|
+
self.current_library_ocr:LibraryOCR = None
|
|
51
|
+
|
|
52
|
+
@abstractmethod
|
|
53
|
+
def image_recognize(self, img:ImageObject) -> ABCTextRecognized:
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
@abstractmethod
|
|
57
|
+
def image_content_data(self, img: ImageObject) -> DataFrame:
|
|
58
|
+
pass
|
|
59
|
+
|
|
60
|
+
@abstractmethod
|
|
61
|
+
def imag_to_string(self, img:ImageObject) -> str:
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def create(
|
|
66
|
+
cls,
|
|
67
|
+
library_ocr:LibraryOCR=LibraryOCR.PYTESSERACT,
|
|
68
|
+
*,
|
|
69
|
+
path_tesseract:File,
|
|
70
|
+
lang:str=None,
|
|
71
|
+
tess_data_dir:Directory=None,
|
|
72
|
+
) -> ABCModuleOcr:
|
|
73
|
+
pass
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from types import ModuleType
|
|
4
|
+
from typing import List, Dict
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import re
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
from ocr_stream.models import (
|
|
10
|
+
ABCModuleOcr,
|
|
11
|
+
ABCTextRecognized,
|
|
12
|
+
LibraryOCR,
|
|
13
|
+
)
|
|
14
|
+
from pandas import DataFrame
|
|
15
|
+
from ocr_stream.utils import (
|
|
16
|
+
PageDocumentPdf, DocumentPdf, LibraryImage, ImageObject, ArrayString, DataString,
|
|
17
|
+
File, Directory
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from pytesseract import pytesseract, Output
|
|
21
|
+
|
|
22
|
+
def get_temp_dir(prefix=Path().home()) -> str:
|
|
23
|
+
prefix = Path().home()
|
|
24
|
+
sys_temp_dir = os.environ.get('TMP', os.path.join(prefix, 'var', 'temp'))
|
|
25
|
+
if not sys_temp_dir:
|
|
26
|
+
sys_temp_dir = os.path.join(prefix, 'var', 'temp')
|
|
27
|
+
if not os.path.exists(sys_temp_dir):
|
|
28
|
+
try:
|
|
29
|
+
os.makedirs(sys_temp_dir)
|
|
30
|
+
except Exception as e:
|
|
31
|
+
print(e)
|
|
32
|
+
os.environ["TEMP"] = sys_temp_dir
|
|
33
|
+
print('-' * 30)
|
|
34
|
+
print(f'Diretório temporário: {sys_temp_dir}')
|
|
35
|
+
print('-' * 30)
|
|
36
|
+
return sys_temp_dir
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class TextRecognizedToi(object):
|
|
40
|
+
"""
|
|
41
|
+
Extração/Filtro de texto em documentos do tipo carta TOI.
|
|
42
|
+
"""
|
|
43
|
+
def __init__(self, value:str=None, *, separator:str='\n', column_text='TEXT', file:File):
|
|
44
|
+
# Todas as linhas que foram reconhecidas em uma imagem/página PDF.
|
|
45
|
+
if not isinstance(value, str):
|
|
46
|
+
raise ValueError(f'{__class__.__name__}Use: str, não {type(value)}')
|
|
47
|
+
self.text_document:str = DataString(value).to_upper().value if value is not None else None
|
|
48
|
+
self.separator:str = separator
|
|
49
|
+
self.file:File = file
|
|
50
|
+
self.column_text:str = column_text
|
|
51
|
+
|
|
52
|
+
self.pattern_line_uc_toi = r'UC:\s*\d+\s*TOI:\s*\d+'
|
|
53
|
+
self.pattern_uc = r'\b(?:UC:?|UC):?\s*(\d+)'
|
|
54
|
+
self.pattern_toi = r'\b(?:TOI?|TO):?\s*(\d+)'
|
|
55
|
+
self.pattern_localidade = r'LOCALIDADE:\s*(.*)'
|
|
56
|
+
|
|
57
|
+
self.words_toi = (
|
|
58
|
+
'TO]!', 'TO]', 'TOl', 'TOI', 'TOI:'
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
self.words_uc = (
|
|
62
|
+
'UE', 'UE:' 'UC', 'UC:', 'JC;'
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
def __replace_chars(self, text, char, new_char) -> str:
|
|
66
|
+
return re.sub(r'{}'.format(char), new_char, text)
|
|
67
|
+
|
|
68
|
+
def __get_match_groups(self, pattern, text:str) -> object | None:
|
|
69
|
+
i = re.search(pattern, text)
|
|
70
|
+
if i is None:
|
|
71
|
+
return None
|
|
72
|
+
return i.groups()
|
|
73
|
+
|
|
74
|
+
def __get_match_group(self, pattern, text:str) -> object | None:
|
|
75
|
+
i = re.search(pattern, text)
|
|
76
|
+
if i is None:
|
|
77
|
+
return None
|
|
78
|
+
return i.group()
|
|
79
|
+
|
|
80
|
+
def is_null(self) -> bool:
|
|
81
|
+
if self.text_document is None:
|
|
82
|
+
return True
|
|
83
|
+
if self.text_document == '':
|
|
84
|
+
return True
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
def to_string(self) -> str | None:
|
|
88
|
+
return DataString(self.text_document).to_upper().value if not self.is_null() else None
|
|
89
|
+
|
|
90
|
+
def to_list(self) -> List[str]:
|
|
91
|
+
return self.text_document.split(self.separator)
|
|
92
|
+
|
|
93
|
+
def to_array_string(self) -> ArrayString:
|
|
94
|
+
values:List[str] = self.to_list()
|
|
95
|
+
|
|
96
|
+
def to_upper(self) -> TextRecognizedToi:
|
|
97
|
+
self.text_document = self.text_document.upper()
|
|
98
|
+
return self
|
|
99
|
+
|
|
100
|
+
def to_dataframe(self) -> DataFrame:
|
|
101
|
+
uc = self.uc()
|
|
102
|
+
toi = self.toi()
|
|
103
|
+
if uc is None:
|
|
104
|
+
uc = 'nan'
|
|
105
|
+
else:
|
|
106
|
+
uc = DataString(uc).replace_bad_chars().replace_all('- ', ' ').replace_all('_', ' ').value.strip()
|
|
107
|
+
#
|
|
108
|
+
if toi is None:
|
|
109
|
+
toi = 'nan'
|
|
110
|
+
else:
|
|
111
|
+
toi = DataString(toi).replace_bad_chars()
|
|
112
|
+
toi = toi.replace_all('- ', '-').replace_all('_', ' ').replace_all('-', ' ').replace_all('TOI', '').value.strip()
|
|
113
|
+
|
|
114
|
+
df = DataFrame()
|
|
115
|
+
df[self.column_text] = self.to_list()
|
|
116
|
+
num = len(df)
|
|
117
|
+
df['UC'] = [uc] * num
|
|
118
|
+
df['TOI'] = [toi] * num
|
|
119
|
+
df['LOCALIDADE'] = [self.localidade()] * num
|
|
120
|
+
df['ARQUIVO'] = [self.file.absolute()] * num
|
|
121
|
+
df['MD5'] = [self.file.md5()] * num
|
|
122
|
+
return df
|
|
123
|
+
|
|
124
|
+
def remove_bad_chars(self) -> TextRecognizedToi:
|
|
125
|
+
values = []
|
|
126
|
+
for item in self.to_list():
|
|
127
|
+
values.append(
|
|
128
|
+
DataString(item).replace_bad_chars(new_char='_').replace_all('/', '-').value
|
|
129
|
+
)
|
|
130
|
+
self.listText = values
|
|
131
|
+
return self
|
|
132
|
+
|
|
133
|
+
def uc(self) -> str:
|
|
134
|
+
"""
|
|
135
|
+
Extrair o número da UC em forma de string, se a operação falhar, será retornado (nan)
|
|
136
|
+
"""
|
|
137
|
+
line_uc_toi = self.line_uc_and_toi()
|
|
138
|
+
uc_value:str = None
|
|
139
|
+
if line_uc_toi is not None:
|
|
140
|
+
uc_value = self.__get_match_group(self.pattern_uc, line_uc_toi)
|
|
141
|
+
if uc_value is not None:
|
|
142
|
+
return uc_value.replace('UC', '')
|
|
143
|
+
|
|
144
|
+
arr = ArrayString(self.text_document.split(' '))
|
|
145
|
+
for w in self.words_uc:
|
|
146
|
+
out = arr.get_next(w).value
|
|
147
|
+
try:
|
|
148
|
+
int(out)
|
|
149
|
+
except:
|
|
150
|
+
pass
|
|
151
|
+
else:
|
|
152
|
+
return out
|
|
153
|
+
return None
|
|
154
|
+
|
|
155
|
+
def toi(self) -> str:
|
|
156
|
+
line_uc_toi = self.line_uc_and_toi()
|
|
157
|
+
toi_value:str = None
|
|
158
|
+
if line_uc_toi is not None:
|
|
159
|
+
toi_value = self.__get_match_group(self.pattern_toi, line_uc_toi)
|
|
160
|
+
if toi_value is not None:
|
|
161
|
+
return toi_value.replace('TOI', '')
|
|
162
|
+
arr = ArrayString(self.text_document.split(' '))
|
|
163
|
+
|
|
164
|
+
for w in self.words_toi:
|
|
165
|
+
out = arr.get_next(w).value
|
|
166
|
+
try:
|
|
167
|
+
int(out)
|
|
168
|
+
except:
|
|
169
|
+
pass
|
|
170
|
+
else:
|
|
171
|
+
return out
|
|
172
|
+
return None
|
|
173
|
+
|
|
174
|
+
def roteiro(self) -> str:
|
|
175
|
+
self.remove_bad_chars()
|
|
176
|
+
pass
|
|
177
|
+
|
|
178
|
+
def localidade(self) -> str:
|
|
179
|
+
lines = self.to_list()
|
|
180
|
+
loc = 'nan'
|
|
181
|
+
for line in lines:
|
|
182
|
+
out = re.search(self.pattern_localidade, line)
|
|
183
|
+
if out:
|
|
184
|
+
loc = out.group(1)
|
|
185
|
+
break
|
|
186
|
+
loc = DataString(loc).replace_all(' ').value
|
|
187
|
+
# Remover "_" do final
|
|
188
|
+
return re.sub(r"_$", "", loc)
|
|
189
|
+
|
|
190
|
+
def line_postagem(self) -> str:
|
|
191
|
+
pass
|
|
192
|
+
|
|
193
|
+
def line_uc_and_toi(self) -> DataString | None:
|
|
194
|
+
line_toi = None
|
|
195
|
+
lines = self.to_list()
|
|
196
|
+
for item in lines:
|
|
197
|
+
out = self.__get_match_group(self.pattern_line_uc_toi, item)
|
|
198
|
+
if out is None:
|
|
199
|
+
continue
|
|
200
|
+
line_toi = out
|
|
201
|
+
break
|
|
202
|
+
return line_toi
|
|
203
|
+
|
|
204
|
+
def line_roteiro(self) -> DataString:
|
|
205
|
+
return DataString(None)
|
|
206
|
+
|
|
207
|
+
#======================================================================#
|
|
208
|
+
# Texto reconhecido de uma imagem.
|
|
209
|
+
#======================================================================#
|
|
210
|
+
class TextRecognized(ABCTextRecognized):
|
|
211
|
+
"""
|
|
212
|
+
Recebe os bytes de uma página PDF reconhecida de imagem
|
|
213
|
+
e exporta para vários tipos de dados.
|
|
214
|
+
-> DataFrame()
|
|
215
|
+
-> str
|
|
216
|
+
-> PageDocumentPdf()
|
|
217
|
+
"""
|
|
218
|
+
def __init__(self, bytes_recognized):
|
|
219
|
+
super().__init__(bytes_recognized)
|
|
220
|
+
|
|
221
|
+
self.list_bad_char:List[str] = [
|
|
222
|
+
':', ',', ';', '$', '=',
|
|
223
|
+
'!', '}', '{', '(', ')',
|
|
224
|
+
'|', '\\', '‘', '*'
|
|
225
|
+
'¢', '“', '\'', '¢', '"',
|
|
226
|
+
'#', '.', '<', '?', '>',
|
|
227
|
+
'»', '@', '+', '[', ']',
|
|
228
|
+
'%', '~', '¥', '♀',
|
|
229
|
+
]
|
|
230
|
+
|
|
231
|
+
def to_string(self) -> str | None:
|
|
232
|
+
return self.to_page_pdf().to_string()
|
|
233
|
+
|
|
234
|
+
def to_page_pdf(self) -> PageDocumentPdf:
|
|
235
|
+
return PageDocumentPdf.create_from_page_bytes(self.bytes_recognized)
|
|
236
|
+
|
|
237
|
+
def to_document(self) -> DocumentPdf:
|
|
238
|
+
doc: DocumentPdf = DocumentPdf()
|
|
239
|
+
doc.add_page(self.to_page_pdf())
|
|
240
|
+
return doc
|
|
241
|
+
|
|
242
|
+
def to_dict(self, separator:str='\n') -> Dict[str, List[str]]:
|
|
243
|
+
image_dict:Dict[str, List[str]] = {
|
|
244
|
+
'TEXT': [],
|
|
245
|
+
'NUM_LINHA': [],
|
|
246
|
+
}
|
|
247
|
+
image_text:str = self.to_string()
|
|
248
|
+
if (image_text is None) or (image_text == ''):
|
|
249
|
+
return {
|
|
250
|
+
'TEXT': ['nan'],
|
|
251
|
+
'NUM_LINHA': ['nan'],
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
image_lines:List[str] = image_text.split(separator)
|
|
255
|
+
for num, line in enumerate(image_lines):
|
|
256
|
+
image_dict['TEXT'].append(line)
|
|
257
|
+
image_dict['NUM_LINHA'].append(num+1)
|
|
258
|
+
return image_dict
|
|
259
|
+
|
|
260
|
+
def to_dataframe(self, column = 'TEXT', separator:str='\n') -> DataFrame:
|
|
261
|
+
return DataFrame(self.to_dict(separator))
|
|
262
|
+
|
|
263
|
+
#======================================================================#
|
|
264
|
+
# Modulo OCR pytesseract
|
|
265
|
+
#======================================================================#
|
|
266
|
+
|
|
267
|
+
class IModulePytesseract(ABCModuleOcr):
|
|
268
|
+
def __init__(self, *, cmd_executable, lang = None, tess_data_dir = None):
|
|
269
|
+
super().__init__(cmd_executable=cmd_executable, lang=lang, tess_data_dir=tess_data_dir)
|
|
270
|
+
self.current_library:LibraryOCR = LibraryOCR.PYTESSERACT
|
|
271
|
+
self._pyTesseract:pytesseract = pytesseract
|
|
272
|
+
self._pyTesseract.tesseract_cmd = self.cmd_executable.absolute()
|
|
273
|
+
|
|
274
|
+
def __get_tess_dir_config(self) -> str | None:
|
|
275
|
+
"""
|
|
276
|
+
https://github.com/h/pytesseract
|
|
277
|
+
|
|
278
|
+
Example config: r'--tessdata-dir "C:\Program Files (x86)\Tesseract-OCR\tessdata"'
|
|
279
|
+
tessdata_dir_config = r'--tessdata-dir <replace_with_your_tessdata_dir_path>'
|
|
280
|
+
It's important to add double quotes around the dir path.
|
|
281
|
+
"""
|
|
282
|
+
#
|
|
283
|
+
# Caminho para os dados de idioma, por, eng etc...
|
|
284
|
+
# os.environ["TESSDATA_PREFIX"] = self.tess_data_dir.absolute()
|
|
285
|
+
if self.tess_data_dir is None:
|
|
286
|
+
return ''
|
|
287
|
+
if not self.tess_data_dir.path.exists():
|
|
288
|
+
return ''
|
|
289
|
+
return r'--tessdata-dir "{}"'.format(self.tess_data_dir.absolute())
|
|
290
|
+
|
|
291
|
+
def imag_to_string(self, img) -> str:
|
|
292
|
+
if img.current_library == LibraryImage.OPENCV:
|
|
293
|
+
text_img:str = self._pyTesseract.image_to_string(
|
|
294
|
+
img.to_image_opencv(),
|
|
295
|
+
lang=self.lang,
|
|
296
|
+
config=self.__get_tess_dir_config()
|
|
297
|
+
)
|
|
298
|
+
else:
|
|
299
|
+
text_img:str = self._pyTesseract.image_to_string(
|
|
300
|
+
img.to_image_pil(),
|
|
301
|
+
lang=self.lang,
|
|
302
|
+
config=self.__get_tess_dir_config()
|
|
303
|
+
)
|
|
304
|
+
return text_img
|
|
305
|
+
|
|
306
|
+
def image_recognize(self, img) -> TextRecognized:
|
|
307
|
+
if img.current_library == LibraryImage.OPENCV:
|
|
308
|
+
pdf_bytes:bytes = self._pyTesseract.image_to_pdf_or_hocr(
|
|
309
|
+
img.to_image_opencv(),
|
|
310
|
+
lang=self.lang,
|
|
311
|
+
config=self.__get_tess_dir_config()
|
|
312
|
+
)
|
|
313
|
+
else:
|
|
314
|
+
pdf_bytes:bytes = self._pyTesseract.image_to_pdf_or_hocr(
|
|
315
|
+
img.to_image_pil(),
|
|
316
|
+
lang=self.lang,
|
|
317
|
+
config=self.__get_tess_dir_config()
|
|
318
|
+
)
|
|
319
|
+
return TextRecognized(pdf_bytes)
|
|
320
|
+
|
|
321
|
+
def image_content_data(self, img) -> DataFrame:
|
|
322
|
+
if img.current_library == LibraryImage.OPENCV:
|
|
323
|
+
text_data:DataFrame = self._pyTesseract.image_to_data(
|
|
324
|
+
img.to_image_opencv(),
|
|
325
|
+
lang=self.lang,
|
|
326
|
+
config=self.__get_tess_dir_config(),
|
|
327
|
+
output_type=Output.DATAFRAME,
|
|
328
|
+
)
|
|
329
|
+
else:
|
|
330
|
+
text_data:DataFrame = self._pyTesseract.image_to_data(
|
|
331
|
+
img.to_image_pil(),
|
|
332
|
+
lang=self.lang,
|
|
333
|
+
config=self.__get_tess_dir_config(),
|
|
334
|
+
output_type=Output.DATAFRAME,
|
|
335
|
+
)
|
|
336
|
+
return text_data
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
#======================================================================#
|
|
340
|
+
# Modulo OCR pyocr
|
|
341
|
+
#======================================================================#
|
|
342
|
+
|
|
343
|
+
class IModulePyOcr(ABCModuleOcr):
|
|
344
|
+
def __init__(self, *, cmd_executable, lang = None, tess_data_dir = None):
|
|
345
|
+
super().__init__(cmd_executable=cmd_executable, lang=lang, tess_data_dir=tess_data_dir)
|
|
346
|
+
self.current_library:LibraryOCR = LibraryOCR.PYOCR
|
|
347
|
+
self.cmd_executable:File = cmd_executable
|
|
348
|
+
self.tess_data_dir:Directory = tess_data_dir
|
|
349
|
+
try:
|
|
350
|
+
import pyocr
|
|
351
|
+
import pyocr.tesseract
|
|
352
|
+
except Exception as e:
|
|
353
|
+
raise (e)
|
|
354
|
+
|
|
355
|
+
pyocr_modules:List[ModuleType] = pyocr.get_available_tools()
|
|
356
|
+
if len(pyocr_modules) == 0:
|
|
357
|
+
raise ValueError(f"{__class__.__name__} No OCR tool found")
|
|
358
|
+
# The tools are returned in the recommended order of usage
|
|
359
|
+
self._pyOcr:pyocr.tesseract = pyocr_modules[0]
|
|
360
|
+
langs:List[str] = self._pyOcr.get_available_languages()
|
|
361
|
+
if lang in lang:
|
|
362
|
+
self.lang = lang
|
|
363
|
+
else:
|
|
364
|
+
self.lang = langs[0]
|
|
365
|
+
|
|
366
|
+
# Ex: Will use tool 'libtesseract'
|
|
367
|
+
print(f"Will use tool {self._pyOcr.get_name()}")
|
|
368
|
+
|
|
369
|
+
def imag_to_string(self, img) -> str:
|
|
370
|
+
return self._pyOcr.image_to_string(
|
|
371
|
+
img.to_image_pil(),
|
|
372
|
+
lang=self.lang,
|
|
373
|
+
builder=pyocr.builders.TextBuilder()
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
def image_recognize(self, img) -> TextRecognized:
|
|
377
|
+
raise NotImplementedError(f'{__class__.__name__} método não implementado')
|
|
378
|
+
|
|
379
|
+
def image_content_data(self, img) -> DataFrame:
|
|
380
|
+
raise NotImplementedError(f'{__class__.__name__} método não implementado')
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
class ModuleOcr(ABCModuleOcr):
|
|
384
|
+
def __init__(self, module_ocr:ABCModuleOcr):
|
|
385
|
+
super().__init__(
|
|
386
|
+
cmd_executable=module_ocr.cmd_executable,
|
|
387
|
+
lang=module_ocr.lang,
|
|
388
|
+
tess_data_dir=module_ocr.tess_data_dir
|
|
389
|
+
)
|
|
390
|
+
self.module_ocr:ABCModuleOcr = module_ocr
|
|
391
|
+
|
|
392
|
+
def image_content_data(self, img:ImageObject) -> DataFrame:
|
|
393
|
+
return self.module_ocr.image_content_data(img)
|
|
394
|
+
|
|
395
|
+
def image_recognize(self, img:ImageObject) -> TextRecognized:
|
|
396
|
+
return self.module_ocr.image_recognize(img)
|
|
397
|
+
|
|
398
|
+
def imag_to_string(self, img) -> str:
|
|
399
|
+
return self.module_ocr.imag_to_string(img)
|
|
400
|
+
|
|
401
|
+
@classmethod
|
|
402
|
+
def create(
|
|
403
|
+
cls,
|
|
404
|
+
library_ocr = LibraryOCR.PYTESSERACT,
|
|
405
|
+
*,
|
|
406
|
+
path_tesseract,
|
|
407
|
+
lang = None,
|
|
408
|
+
tess_data_dir = None
|
|
409
|
+
) -> ModuleOcr:
|
|
410
|
+
#
|
|
411
|
+
if library_ocr == LibraryOCR.PYTESSERACT:
|
|
412
|
+
_module_ocr = IModulePytesseract(cmd_executable=path_tesseract, lang=lang, tess_data_dir=tess_data_dir)
|
|
413
|
+
elif library_ocr == LibraryOCR.PYOCR:
|
|
414
|
+
_module_ocr = IModulePyOcr(cmd_executable=path_tesseract, lang=lang, tess_data_dir=tess_data_dir)
|
|
415
|
+
else:
|
|
416
|
+
raise NotImplementedError(f'{__class__.__name__}\nLibraryOcr não implementada: {library_ocr}')
|
|
417
|
+
return cls(_module_ocr)
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
#
|
|
3
|
+
from pandas import DataFrame
|
|
4
|
+
from soup_files import (
|
|
5
|
+
File, Directory, UserAppDir, UserFileSystem, InputFiles,
|
|
6
|
+
JsonConvert, JsonData
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
from convert_stream import (
|
|
10
|
+
LibraryDates, LibraryImage, LibraryPDF, ImageObject,
|
|
11
|
+
PdfStream, ImageStream,PageDocumentPdf, DocumentPdf,
|
|
12
|
+
ArrayString, DataString, ConvertDate, print_line, print_title
|
|
13
|
+
)
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ocr_stream
|
|
3
|
+
Version: 1.1
|
|
4
|
+
Summary: Extrair textos de documentos digitalizados e imagens.
|
|
5
|
+
Author: Bruno Chaves
|
|
6
|
+
Requires: PyPDF2
|
|
7
|
+
Requires: PyMuPDF
|
|
8
|
+
Requires: reportlab
|
|
9
|
+
Requires: openpyxl
|
|
10
|
+
Requires: openpyxl
|
|
11
|
+
Requires: pandas
|
|
12
|
+
Requires: Pillow
|
|
13
|
+
Requires: opencv_python
|
|
14
|
+
Requires: requests
|
|
15
|
+
Requires: pytesseract
|
|
16
|
+
Requires-Python: >=3.11
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
Requires-Dist: soup_files==1.0.1
|
|
19
|
+
Requires-Dist: PyPDF2==3.0.1
|
|
20
|
+
Requires-Dist: PyMuPDF==1.25.5
|
|
21
|
+
Requires-Dist: reportlab==4.3.1
|
|
22
|
+
Requires-Dist: openpyxl==3.1.5
|
|
23
|
+
Requires-Dist: pandas==2.2.3
|
|
24
|
+
Requires-Dist: Pillow==11.2.1
|
|
25
|
+
Requires-Dist: opencv-python==4.11.0.86
|
|
26
|
+
Requires-Dist: convert_stream==1.1.1
|
|
27
|
+
Dynamic: requires
|
|
28
|
+
|
|
29
|
+
# ocrlib
|
|
30
|
+
|
|
31
|
+
# Uso simples
|
|
32
|
+
|
|
33
|
+
from ocrlib.utils import File, DocumentPdf
|
|
34
|
+
from ocrlib import RecognizeImage
|
|
35
|
+
|
|
36
|
+
# passo 1 instânciar o objeto para reconhecer texto, ultilzaremos o caminho do tesseract
|
|
37
|
+
# Substitua pelo tesseract do seu sistema
|
|
38
|
+
|
|
39
|
+
tess = File('/usr/bin/tesseract')
|
|
40
|
+
ocr = RecognizeImage.create(path_tesseract=tess)
|
|
41
|
+
|
|
42
|
+
# passo 2 instânciar um arquivo de imagem para extrair o texto.
|
|
43
|
+
image = File('path/to/file.png')
|
|
44
|
+
|
|
45
|
+
# passo 3 extrair o texto
|
|
46
|
+
text = ocr.image_to_string(image)
|
|
47
|
+
print(text)
|
|
48
|
+
|
|
49
|
+
# passo 4 opcional - você pode salvar um arquivo PDF com o texto extraido
|
|
50
|
+
output_file = File('path/to/save.pdf')
|
|
51
|
+
recognized = ocr.image_recognize(image)
|
|
52
|
+
recognized.to_document().to_file_pdf(output_file)
|
|
53
|
+
|
|
54
|
+
# passo 5 opcional - você pode salvar uma planilha com o texto da imagem
|
|
55
|
+
output_excel = File('path/to/file.xlsx')
|
|
56
|
+
recognized = ocr.image_recognize(image)
|
|
57
|
+
recognized.to_document().to_excel(output_excel)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
ocr_stream/__init__.py,sha256=cukkDxwmn2Kw-0apnpklR6nfbxZ4Sss8advGz2RpTGQ,224
|
|
2
|
+
ocr_stream/__main__.py,sha256=vXjP4QOLSP_jCCl2ymGXcFSZKUVtr96T4soM61oLRmU,1169
|
|
3
|
+
ocr_stream/_version.py,sha256=qRXc4Bg1d7fbAfm5NPtX06BqagIXnMYagMnA48keoU4,77
|
|
4
|
+
ocr_stream/extractors.py,sha256=JQTcrLwo5vSvw3FoXCCbv3kN7eR2nDs48eAo3xNJJUM,3629
|
|
5
|
+
ocr_stream/modules_ocr.py,sha256=PHPvRV6Onhj_zTHWZ724voKgXCv6F3HHWmRMZkqom-o,14996
|
|
6
|
+
ocr_stream/models/__init__.py,sha256=ehyOznjUt72rBZ__xREJpf2VKwpuq0Vf1z2MYDBHgj0,137
|
|
7
|
+
ocr_stream/models/m_extractors.py,sha256=cbasB5S8K25fHfNPxGWhpYA6lBfAl-PqYXaMZRf4AcY,1098
|
|
8
|
+
ocr_stream/models/m_modules_ocr.py,sha256=F5042F3lQAk3Aeyac_fxWPiZaWjZya6W6_7dOZ5PyEo,2155
|
|
9
|
+
ocr_stream/utils/__init__.py,sha256=ywM497Hyz_mg0yVjM5BWRJYjAo9I_e8n-areu0iRjG4,381
|
|
10
|
+
ocr_stream-1.1.dist-info/METADATA,sha256=F2vkDKub96Ta1zga2SkfnmWdKv_OKPb_Onh-Q-lhqRU,1603
|
|
11
|
+
ocr_stream-1.1.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
|
|
12
|
+
ocr_stream-1.1.dist-info/top_level.txt,sha256=P8kJ6573XVRx0Sr3lDXhEgKVOCBbGAxc5cqMSRq9Udg,11
|
|
13
|
+
ocr_stream-1.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ocr_stream
|