ocr-stream 1.2__tar.gz → 1.4__tar.gz
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.
- {ocr_stream-1.2 → ocr_stream-1.4}/PKG-INFO +9 -9
- {ocr_stream-1.2 → ocr_stream-1.4}/ocr_stream/__init__.py +1 -1
- ocr_stream-1.4/ocr_stream/_version.py +5 -0
- ocr_stream-1.4/ocr_stream/extractors.py +126 -0
- {ocr_stream-1.2 → ocr_stream-1.4}/ocr_stream/models/__init__.py +0 -1
- ocr_stream-1.4/ocr_stream/models/m_extractors.py +2 -0
- {ocr_stream-1.2 → ocr_stream-1.4}/ocr_stream/models/m_modules_ocr.py +27 -38
- {ocr_stream-1.2 → ocr_stream-1.4}/ocr_stream/modules_ocr.py +225 -168
- ocr_stream-1.4/ocr_stream/utils/__init__.py +16 -0
- {ocr_stream-1.2 → ocr_stream-1.4}/ocr_stream.egg-info/PKG-INFO +9 -9
- ocr_stream-1.4/ocr_stream.egg-info/requires.txt +9 -0
- {ocr_stream-1.2 → ocr_stream-1.4}/pyproject.toml +10 -9
- ocr_stream-1.2/ocr_stream/_version.py +0 -5
- ocr_stream-1.2/ocr_stream/extractors.py +0 -108
- ocr_stream-1.2/ocr_stream/models/m_extractors.py +0 -39
- ocr_stream-1.2/ocr_stream/utils/__init__.py +0 -13
- ocr_stream-1.2/ocr_stream.egg-info/requires.txt +0 -9
- {ocr_stream-1.2 → ocr_stream-1.4}/README.md +0 -0
- {ocr_stream-1.2 → ocr_stream-1.4}/ocr_stream/__main__.py +0 -0
- {ocr_stream-1.2 → ocr_stream-1.4}/ocr_stream.egg-info/SOURCES.txt +0 -0
- {ocr_stream-1.2 → ocr_stream-1.4}/ocr_stream.egg-info/dependency_links.txt +0 -0
- {ocr_stream-1.2 → ocr_stream-1.4}/ocr_stream.egg-info/not-zip-safe +0 -0
- {ocr_stream-1.2 → ocr_stream-1.4}/ocr_stream.egg-info/top_level.txt +0 -0
- {ocr_stream-1.2 → ocr_stream-1.4}/setup.cfg +0 -0
- {ocr_stream-1.2 → ocr_stream-1.4}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ocr_stream
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4
|
|
4
4
|
Summary: Extrair textos de documentos digitalizados e imagens.
|
|
5
5
|
Author: Bruno Chaves
|
|
6
6
|
Requires: PyPDF2
|
|
@@ -17,14 +17,14 @@ Requires: soup_files
|
|
|
17
17
|
Requires: convert_stream
|
|
18
18
|
Requires-Python: >=3.11
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
|
-
Requires-Dist:
|
|
21
|
-
Requires-Dist:
|
|
22
|
-
Requires-Dist:
|
|
23
|
-
Requires-Dist:
|
|
24
|
-
Requires-Dist:
|
|
25
|
-
Requires-Dist:
|
|
26
|
-
Requires-Dist: opencv-python
|
|
27
|
-
Requires-Dist: convert_stream
|
|
20
|
+
Requires-Dist: PyMuPDF
|
|
21
|
+
Requires-Dist: reportlab
|
|
22
|
+
Requires-Dist: openpyxl
|
|
23
|
+
Requires-Dist: pandas
|
|
24
|
+
Requires-Dist: Pillow>=11.3.0
|
|
25
|
+
Requires-Dist: requests>=2.32.4
|
|
26
|
+
Requires-Dist: opencv-python
|
|
27
|
+
Requires-Dist: convert_stream>=1.4
|
|
28
28
|
Requires-Dist: soup_files
|
|
29
29
|
Dynamic: requires
|
|
30
30
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
2
|
|
|
3
3
|
from .models.m_modules_ocr import LibraryOCR
|
|
4
|
-
from .modules_ocr import TextRecognized
|
|
4
|
+
from .modules_ocr import TextRecognized, BinaryTesseract
|
|
5
5
|
from .utils import File, Directory, InputFiles, UserFileSystem
|
|
6
6
|
from .extractors import RecognizeImage, RecognizePdf
|
|
7
7
|
from ._version import __version__, __modify_data__
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from typing import List
|
|
4
|
+
from ocr_stream.utils import (
|
|
5
|
+
File, ImageObject,
|
|
6
|
+
DataFrame, PageDocumentPdf, DocumentPdf,
|
|
7
|
+
)
|
|
8
|
+
from ocr_stream.models import LibraryOCR
|
|
9
|
+
from ocr_stream.modules_ocr import ModuleOcr, TextRecognized, BinaryTesseract
|
|
10
|
+
from convert_stream import ConvertPdfToImage, CreatePbar
|
|
11
|
+
from soup_files import ProgressBarAdapter
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class RecognizeImage(object):
|
|
15
|
+
"""
|
|
16
|
+
Reconhecer textos em imagens com pytesseract|pyocr usando o tesseract
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, module_ocr):
|
|
20
|
+
super().__init__()
|
|
21
|
+
self.module_ocr: ModuleOcr = module_ocr
|
|
22
|
+
|
|
23
|
+
def image_content_data(self, img: ImageObject | File) -> DataFrame:
|
|
24
|
+
"""
|
|
25
|
+
Retorna uma tabela estruturada com os dados reconhecidos da imagem.
|
|
26
|
+
|
|
27
|
+
Este método extrai as informações contidas em uma imagem e as organiza em
|
|
28
|
+
um DataFrame com colunas como o texto detectado, coordenadas da caixa delimitadora,
|
|
29
|
+
nível do OCR e confiabilidade, entre outras.
|
|
30
|
+
|
|
31
|
+
Parâmetros:
|
|
32
|
+
img (ImageObject | File): A imagem a ser processada, podendo ser um objeto
|
|
33
|
+
`ImageObject` ou um arquivo `File`.
|
|
34
|
+
|
|
35
|
+
Retorna:
|
|
36
|
+
DataFrame: Uma tabela contendo os dados reconhecidos na imagem.
|
|
37
|
+
|
|
38
|
+
Lança:
|
|
39
|
+
ValueError: Se o tipo do parâmetro `img` não for `ImageObject` ou `File`.
|
|
40
|
+
|
|
41
|
+
@param img: Imagem a ser processada, podendo ser uma instância de `ImageObject`
|
|
42
|
+
ou um arquivo `File`.
|
|
43
|
+
@type img: ImageObject | File
|
|
44
|
+
|
|
45
|
+
@rtype: pandas.DataFrame
|
|
46
|
+
@return: Um DataFrame com os dados reconhecidos na imagem.
|
|
47
|
+
|
|
48
|
+
@raise ValueError: Caso o tipo de `img` não seja `ImageObject` nem `File`.
|
|
49
|
+
"""
|
|
50
|
+
if isinstance(img, File):
|
|
51
|
+
return self.module_ocr.image_content_data(ImageObject.create_from_file(img))
|
|
52
|
+
elif isinstance(img, ImageObject):
|
|
53
|
+
return self.module_ocr.image_content_data(img)
|
|
54
|
+
else:
|
|
55
|
+
raise ValueError(f'{__class__.__name__}\nUse: ImageObject() ou File(), não {type(img)}')
|
|
56
|
+
|
|
57
|
+
def image_recognize(self, img: ImageObject | File) -> TextRecognized:
|
|
58
|
+
if isinstance(img, File):
|
|
59
|
+
return self.module_ocr.image_recognize(ImageObject.create_from_file(img))
|
|
60
|
+
elif isinstance(img, ImageObject):
|
|
61
|
+
return self.module_ocr.image_recognize(img)
|
|
62
|
+
else:
|
|
63
|
+
raise ValueError(f'{__class__.__name__}\nUse: ImageObject() ou File(), não {type(img)}')
|
|
64
|
+
|
|
65
|
+
def image_to_string(self, img: ImageObject | File) -> str:
|
|
66
|
+
if isinstance(img, File):
|
|
67
|
+
return self.module_ocr.imag_to_string(ImageObject.create_from_file(img))
|
|
68
|
+
elif isinstance(img, ImageObject):
|
|
69
|
+
return self.module_ocr.imag_to_string(img)
|
|
70
|
+
else:
|
|
71
|
+
raise ValueError(f'{__class__.__name__}\nUse: ImageObject() ou File(), não {type(img)}')
|
|
72
|
+
|
|
73
|
+
@classmethod
|
|
74
|
+
def create(
|
|
75
|
+
cls,
|
|
76
|
+
library_ocr: LibraryOCR = LibraryOCR.PYTESSERACT,
|
|
77
|
+
*,
|
|
78
|
+
binary_tess: BinaryTesseract = BinaryTesseract(),
|
|
79
|
+
) -> RecognizeImage:
|
|
80
|
+
#
|
|
81
|
+
module_ocr = ModuleOcr.create(library_ocr, binary_tess=binary_tess)
|
|
82
|
+
return cls(module_ocr)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class RecognizePdf(object):
|
|
86
|
+
def __init__(
|
|
87
|
+
self,
|
|
88
|
+
recognize_image: RecognizeImage, *,
|
|
89
|
+
pbar: ProgressBarAdapter = CreatePbar().get()
|
|
90
|
+
):
|
|
91
|
+
self.recognize_image: RecognizeImage = recognize_image
|
|
92
|
+
self.pdf_to_image: ConvertPdfToImage = ConvertPdfToImage.create()
|
|
93
|
+
self.pbar: ProgressBarAdapter = pbar
|
|
94
|
+
|
|
95
|
+
def recognize_page_pdf(self, page: PageDocumentPdf) -> PageDocumentPdf:
|
|
96
|
+
"""
|
|
97
|
+
Converte a página em Imagem, reconhece o texto com OCR e
|
|
98
|
+
retorna uma nova página com o texto reconhecido.
|
|
99
|
+
"""
|
|
100
|
+
img: ImageObject = self.pdf_to_image.from_page_pdf(page)
|
|
101
|
+
text_recognized: TextRecognized = self.recognize_image.image_recognize(img)
|
|
102
|
+
return text_recognized.to_page_pdf()
|
|
103
|
+
|
|
104
|
+
def recognize_document(self, doc: DocumentPdf) -> DocumentPdf:
|
|
105
|
+
new_pages: List[PageDocumentPdf] = []
|
|
106
|
+
|
|
107
|
+
for n, page in enumerate(doc.get_pages()):
|
|
108
|
+
self.pbar.update(
|
|
109
|
+
((n+1)/doc.get_num_pages()) * 100,
|
|
110
|
+
f'Reconhecendo página PDF [{n+1} de {doc.get_num_pages()}]',
|
|
111
|
+
)
|
|
112
|
+
recognized_page: PageDocumentPdf = self.recognize_page_pdf(page)
|
|
113
|
+
new_pages.append(recognized_page)
|
|
114
|
+
return DocumentPdf(pages=new_pages)
|
|
115
|
+
|
|
116
|
+
@classmethod
|
|
117
|
+
def create(
|
|
118
|
+
cls,
|
|
119
|
+
library_ocr=LibraryOCR.PYTESSERACT,
|
|
120
|
+
*,
|
|
121
|
+
binary_tess: BinaryTesseract = BinaryTesseract(),
|
|
122
|
+
pbar: ProgressBarAdapter = CreatePbar().get(),
|
|
123
|
+
) -> RecognizePdf:
|
|
124
|
+
#
|
|
125
|
+
recognize_image = RecognizeImage.create(library_ocr, binary_tess=binary_tess)
|
|
126
|
+
return cls(recognize_image, pbar=pbar)
|
|
@@ -8,72 +8,61 @@ from pandas import DataFrame
|
|
|
8
8
|
from soup_files import File, Directory
|
|
9
9
|
from convert_stream import ImageObject, DocumentPdf, PageDocumentPdf, LibraryImage
|
|
10
10
|
|
|
11
|
+
|
|
11
12
|
class LibraryOCR(Enum):
|
|
12
13
|
PYTESSERACT = 'pytesseract'
|
|
13
14
|
PYOCR = 'pyocr'
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
|
|
16
|
+
|
|
16
17
|
class ABCTextRecognized(ABC):
|
|
17
|
-
def __init__(self, bytes_recognized:bytes):
|
|
18
|
+
def __init__(self, bytes_recognized: bytes):
|
|
18
19
|
super().__init__()
|
|
19
|
-
self.bytes_recognized:bytes = bytes_recognized
|
|
20
|
-
|
|
20
|
+
self.bytes_recognized: bytes = bytes_recognized
|
|
21
|
+
|
|
21
22
|
@abstractmethod
|
|
22
23
|
def to_string(self) -> str:
|
|
23
24
|
pass
|
|
24
|
-
|
|
25
|
+
|
|
25
26
|
@abstractmethod
|
|
26
27
|
def to_page_pdf(self) -> PageDocumentPdf:
|
|
27
28
|
pass
|
|
28
|
-
|
|
29
|
+
|
|
29
30
|
@abstractmethod
|
|
30
31
|
def to_document(self) -> DocumentPdf:
|
|
31
32
|
pass
|
|
32
|
-
|
|
33
|
+
|
|
33
34
|
@abstractmethod
|
|
34
|
-
def to_dataframe(self, separator:str='\n', column_text: str = 'TEXT') -> DataFrame:
|
|
35
|
+
def to_dataframe(self, separator: str = '\n', column_text: str = 'TEXT') -> DataFrame:
|
|
35
36
|
pass
|
|
36
|
-
|
|
37
|
+
|
|
37
38
|
@abstractmethod
|
|
38
|
-
def to_dict(self, separator:str='\n', column_text: str = 'TEXT') -> Dict[str, List[str]]:
|
|
39
|
+
def to_dict(self, separator: str = '\n', column_text: str = 'TEXT') -> Dict[str, List[str]]:
|
|
39
40
|
pass
|
|
40
|
-
|
|
41
|
-
|
|
41
|
+
|
|
42
|
+
|
|
42
43
|
#======================================================================#
|
|
43
44
|
# Abstração para o módulo que extrai o texto das imagens (OCR)
|
|
44
45
|
# pode ser implementado com pytesseract ou outros.
|
|
45
46
|
#======================================================================#
|
|
47
|
+
|
|
48
|
+
|
|
46
49
|
class ABCModuleOcr(ABC):
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
self.
|
|
50
|
-
self.
|
|
51
|
-
self.
|
|
52
|
-
|
|
50
|
+
|
|
51
|
+
def __init__(self, *, cmd_executable: File, lang: str = None, tess_data_dir: Directory = None):
|
|
52
|
+
self.cmd_executable: File = cmd_executable
|
|
53
|
+
self.lang: str = lang
|
|
54
|
+
self.tess_data_dir: Directory = tess_data_dir
|
|
55
|
+
self.current_library_ocr: LibraryOCR = None
|
|
56
|
+
|
|
53
57
|
@abstractmethod
|
|
54
|
-
def image_recognize(self, img:ImageObject) -> ABCTextRecognized:
|
|
58
|
+
def image_recognize(self, img: ImageObject) -> ABCTextRecognized:
|
|
55
59
|
pass
|
|
56
|
-
|
|
60
|
+
|
|
57
61
|
@abstractmethod
|
|
58
62
|
def image_content_data(self, img: ImageObject) -> DataFrame:
|
|
59
63
|
pass
|
|
60
|
-
|
|
64
|
+
|
|
61
65
|
@abstractmethod
|
|
62
|
-
def imag_to_string(self, img:ImageObject) -> str:
|
|
63
|
-
pass
|
|
64
|
-
|
|
65
|
-
@classmethod
|
|
66
|
-
def create(
|
|
67
|
-
cls,
|
|
68
|
-
library_ocr:LibraryOCR=LibraryOCR.PYTESSERACT,
|
|
69
|
-
*,
|
|
70
|
-
path_tesseract:File,
|
|
71
|
-
lang:str=None,
|
|
72
|
-
tess_data_dir:Directory=None,
|
|
73
|
-
) -> ABCModuleOcr:
|
|
66
|
+
def imag_to_string(self, img: ImageObject) -> str:
|
|
74
67
|
pass
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
68
|
|
|
79
|
-
|
|
@@ -2,99 +2,93 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
from types import ModuleType
|
|
4
4
|
from typing import List, Dict
|
|
5
|
-
from
|
|
5
|
+
from shutil import which
|
|
6
6
|
import re
|
|
7
7
|
import os
|
|
8
8
|
from pandas import DataFrame
|
|
9
9
|
from pytesseract import pytesseract, Output
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
from ocr_stream.models import (
|
|
11
12
|
ABCModuleOcr, ABCTextRecognized, LibraryOCR,
|
|
12
13
|
)
|
|
14
|
+
|
|
13
15
|
from ocr_stream.utils import (
|
|
14
16
|
PageDocumentPdf, DocumentPdf, LibraryImage, LibraryPDF,
|
|
15
|
-
ImageObject,
|
|
17
|
+
ImageObject, DataString, File, Directory,
|
|
18
|
+
ColumnTable, KERNEL_TYPE, ArrayString,
|
|
16
19
|
)
|
|
17
20
|
|
|
21
|
+
try:
|
|
22
|
+
import pyocr
|
|
23
|
+
except Exception as e:
|
|
24
|
+
print(e)
|
|
18
25
|
|
|
19
|
-
|
|
20
|
-
def get_temp_dir(prefix=Path().home()) -> str:
|
|
21
|
-
prefix = Path().home()
|
|
22
|
-
sys_temp_dir = os.environ.get('TMP', os.path.join(prefix, 'var', 'temp'))
|
|
23
|
-
if not sys_temp_dir:
|
|
24
|
-
sys_temp_dir = os.path.join(prefix, 'var', 'temp')
|
|
25
|
-
if not os.path.exists(sys_temp_dir):
|
|
26
|
-
try:
|
|
27
|
-
os.makedirs(sys_temp_dir)
|
|
28
|
-
except Exception as e:
|
|
29
|
-
print(e)
|
|
30
|
-
os.environ["TEMP"] = sys_temp_dir
|
|
31
|
-
print('-' * 30)
|
|
32
|
-
print(f'Diretório temporário: {sys_temp_dir}')
|
|
33
|
-
print('-' * 30)
|
|
34
|
-
return sys_temp_dir
|
|
35
|
-
|
|
36
|
-
|
|
37
26
|
class TextRecognizedToi(object):
|
|
38
27
|
"""
|
|
39
28
|
Extração/Filtro de texto em documentos do tipo carta TOI.
|
|
40
29
|
"""
|
|
41
|
-
|
|
42
|
-
|
|
30
|
+
|
|
31
|
+
def __init__(self, value: str = None, *, separator: str = '\n', column_text='TEXT', file: File):
|
|
32
|
+
# Todas as linhas reconhecidas em imagem/página PDF.
|
|
43
33
|
if not isinstance(value, str):
|
|
44
34
|
raise ValueError(f'{__class__.__name__}Use: str, não {type(value)}')
|
|
45
|
-
self.text_document:str = DataString(value).to_upper().value if value is not None else None
|
|
46
|
-
self.separator:str = separator
|
|
47
|
-
self.file:File = file
|
|
48
|
-
self.column_text:str = column_text
|
|
49
|
-
|
|
35
|
+
self.text_document: str = DataString(value).to_upper().value if value is not None else None
|
|
36
|
+
self.separator: str = separator
|
|
37
|
+
self.file: File = file
|
|
38
|
+
self.column_text: str = column_text
|
|
39
|
+
self.listText = []
|
|
50
40
|
self.pattern_line_uc_toi = r'UC:\s*\d+\s*TOI:\s*\d+'
|
|
51
41
|
self.pattern_uc = r'\b(?:UC:?|UC):?\s*(\d+)'
|
|
52
42
|
self.pattern_toi = r'\b(?:TOI?|TO):?\s*(\d+)'
|
|
53
43
|
self.pattern_localidade = r'LOCALIDADE:\s*(.*)'
|
|
54
|
-
|
|
44
|
+
|
|
55
45
|
self.words_toi = (
|
|
56
46
|
'TO]!', 'TO]', 'TOl', 'TOI', 'TOI:'
|
|
57
47
|
)
|
|
58
|
-
|
|
48
|
+
|
|
59
49
|
self.words_uc = (
|
|
60
50
|
'UE', 'UE:' 'UC', 'UC:', 'JC;'
|
|
61
51
|
)
|
|
62
|
-
|
|
52
|
+
|
|
63
53
|
def __replace_chars(self, text, char, new_char) -> str:
|
|
64
54
|
return re.sub(r'{}'.format(char), new_char, text)
|
|
65
|
-
|
|
66
|
-
def __get_match_groups(self, pattern, text:str) -> object | None:
|
|
55
|
+
|
|
56
|
+
def __get_match_groups(self, pattern, text: str) -> object | None:
|
|
67
57
|
i = re.search(pattern, text)
|
|
68
58
|
if i is None:
|
|
69
59
|
return None
|
|
70
60
|
return i.groups()
|
|
71
|
-
|
|
72
|
-
def __get_match_group(self, pattern, text:str) -> object | None:
|
|
61
|
+
|
|
62
|
+
def __get_match_group(self, pattern, text: str) -> object | None:
|
|
73
63
|
i = re.search(pattern, text)
|
|
74
64
|
if i is None:
|
|
75
65
|
return None
|
|
76
66
|
return i.group()
|
|
77
|
-
|
|
67
|
+
|
|
78
68
|
def is_null(self) -> bool:
|
|
79
69
|
if self.text_document is None:
|
|
80
70
|
return True
|
|
81
71
|
if self.text_document == '':
|
|
82
72
|
return True
|
|
83
73
|
return False
|
|
84
|
-
|
|
74
|
+
|
|
85
75
|
def to_string(self) -> str | None:
|
|
86
76
|
return DataString(self.text_document).to_upper().value if not self.is_null() else None
|
|
87
|
-
|
|
77
|
+
|
|
88
78
|
def to_list(self) -> List[str]:
|
|
89
79
|
return self.text_document.split(self.separator)
|
|
90
|
-
|
|
80
|
+
|
|
91
81
|
def to_array_string(self) -> ArrayString:
|
|
92
|
-
|
|
93
|
-
|
|
82
|
+
try:
|
|
83
|
+
return ArrayString(self.to_list())
|
|
84
|
+
except Exception as e:
|
|
85
|
+
print(e)
|
|
86
|
+
return ArrayString([])
|
|
87
|
+
|
|
94
88
|
def to_upper(self) -> TextRecognizedToi:
|
|
95
89
|
self.text_document = self.text_document.upper()
|
|
96
90
|
return self
|
|
97
|
-
|
|
91
|
+
|
|
98
92
|
def to_dataframe(self) -> DataFrame:
|
|
99
93
|
uc = self.uc()
|
|
100
94
|
toi = self.toi()
|
|
@@ -107,8 +101,9 @@ class TextRecognizedToi(object):
|
|
|
107
101
|
toi = 'nan'
|
|
108
102
|
else:
|
|
109
103
|
toi = DataString(toi).replace_bad_chars()
|
|
110
|
-
toi = toi.replace_all('- ', '-').replace_all('_', ' ').replace_all('-', ' ').replace_all('TOI',
|
|
111
|
-
|
|
104
|
+
toi = toi.replace_all('- ', '-').replace_all('_', ' ').replace_all('-', ' ').replace_all('TOI',
|
|
105
|
+
'').value.strip()
|
|
106
|
+
|
|
112
107
|
df = DataFrame()
|
|
113
108
|
df[self.column_text] = self.to_list()
|
|
114
109
|
num = len(df)
|
|
@@ -118,7 +113,7 @@ class TextRecognizedToi(object):
|
|
|
118
113
|
df['ARQUIVO'] = [self.file.absolute()] * num
|
|
119
114
|
df['MD5'] = [self.file.md5()] * num
|
|
120
115
|
return df
|
|
121
|
-
|
|
116
|
+
|
|
122
117
|
def remove_bad_chars(self) -> TextRecognizedToi:
|
|
123
118
|
values = []
|
|
124
119
|
for item in self.to_list():
|
|
@@ -127,21 +122,22 @@ class TextRecognizedToi(object):
|
|
|
127
122
|
)
|
|
128
123
|
self.listText = values
|
|
129
124
|
return self
|
|
130
|
-
|
|
131
|
-
def uc(self) -> str:
|
|
125
|
+
|
|
126
|
+
def uc(self) -> str | None:
|
|
132
127
|
"""
|
|
133
128
|
Extrair o número da UC em forma de string, se a operação falhar, será retornado (nan)
|
|
134
129
|
"""
|
|
135
130
|
line_uc_toi = self.line_uc_and_toi()
|
|
136
|
-
|
|
131
|
+
|
|
132
|
+
uc_value: str = None
|
|
137
133
|
if line_uc_toi is not None:
|
|
138
|
-
uc_value = self.__get_match_group(self.pattern_uc, line_uc_toi)
|
|
134
|
+
uc_value: str = self.__get_match_group(self.pattern_uc, line_uc_toi.value)
|
|
139
135
|
if uc_value is not None:
|
|
140
136
|
return uc_value.replace('UC', '')
|
|
141
|
-
|
|
137
|
+
|
|
142
138
|
arr = ArrayString(self.text_document.split(' '))
|
|
143
139
|
for w in self.words_uc:
|
|
144
|
-
out = arr.get_next(w).value
|
|
140
|
+
out: str = arr.get_next(w).value
|
|
145
141
|
try:
|
|
146
142
|
int(out)
|
|
147
143
|
except:
|
|
@@ -149,16 +145,19 @@ class TextRecognizedToi(object):
|
|
|
149
145
|
else:
|
|
150
146
|
return out
|
|
151
147
|
return None
|
|
152
|
-
|
|
153
|
-
def toi(self) -> str:
|
|
148
|
+
|
|
149
|
+
def toi(self) -> str | None:
|
|
154
150
|
line_uc_toi = self.line_uc_and_toi()
|
|
155
|
-
|
|
151
|
+
if line_uc_toi is None:
|
|
152
|
+
return None
|
|
153
|
+
|
|
154
|
+
toi_value: str = None
|
|
156
155
|
if line_uc_toi is not None:
|
|
157
|
-
toi_value = self.__get_match_group(self.pattern_toi, line_uc_toi)
|
|
156
|
+
toi_value = self.__get_match_group(self.pattern_toi, line_uc_toi.value)
|
|
158
157
|
if toi_value is not None:
|
|
159
158
|
return toi_value.replace('TOI', '')
|
|
160
159
|
arr = ArrayString(self.text_document.split(' '))
|
|
161
|
-
|
|
160
|
+
|
|
162
161
|
for w in self.words_toi:
|
|
163
162
|
out = arr.get_next(w).value
|
|
164
163
|
try:
|
|
@@ -168,7 +167,7 @@ class TextRecognizedToi(object):
|
|
|
168
167
|
else:
|
|
169
168
|
return out
|
|
170
169
|
return None
|
|
171
|
-
|
|
170
|
+
|
|
172
171
|
def roteiro(self) -> str:
|
|
173
172
|
self.remove_bad_chars()
|
|
174
173
|
pass
|
|
@@ -184,10 +183,10 @@ class TextRecognizedToi(object):
|
|
|
184
183
|
loc = DataString(loc).replace_all(' ').value
|
|
185
184
|
# Remover "_" do final
|
|
186
185
|
return re.sub(r"_$", "", loc)
|
|
187
|
-
|
|
186
|
+
|
|
188
187
|
def line_postagem(self) -> str:
|
|
189
188
|
pass
|
|
190
|
-
|
|
189
|
+
|
|
191
190
|
def line_uc_and_toi(self) -> DataString | None:
|
|
192
191
|
line_toi = None
|
|
193
192
|
lines = self.to_list()
|
|
@@ -198,9 +197,9 @@ class TextRecognizedToi(object):
|
|
|
198
197
|
line_toi = out
|
|
199
198
|
break
|
|
200
199
|
return line_toi
|
|
201
|
-
|
|
200
|
+
|
|
202
201
|
def line_roteiro(self) -> DataString:
|
|
203
|
-
return DataString(None)
|
|
202
|
+
return DataString(None)
|
|
204
203
|
|
|
205
204
|
|
|
206
205
|
#======================================================================#
|
|
@@ -216,66 +215,125 @@ class TextRecognized(ABCTextRecognized):
|
|
|
216
215
|
-> str
|
|
217
216
|
-> PageDocumentPdf()
|
|
218
217
|
"""
|
|
218
|
+
|
|
219
219
|
def __init__(self, bytes_recognized: bytes):
|
|
220
220
|
super().__init__(bytes_recognized)
|
|
221
|
-
|
|
221
|
+
|
|
222
222
|
self.list_bad_char: List[str] = [
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
'¢', '“', '\'', '¢', '"',
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
223
|
+
':', ',', ';', '$', '=',
|
|
224
|
+
'!', '}', '{', '(', ')',
|
|
225
|
+
'|', '\\', '‘', '*'
|
|
226
|
+
'¢', '“', '\'', '¢', '"',
|
|
227
|
+
'#', '.', '<', '?', '>',
|
|
228
|
+
'»', '@', '+', '[', ']',
|
|
229
|
+
'%', '~', '¥', '♀',
|
|
230
230
|
]
|
|
231
|
-
|
|
231
|
+
|
|
232
232
|
def to_string(self) -> str | None:
|
|
233
233
|
return self.to_page_pdf().to_string()
|
|
234
|
-
|
|
234
|
+
|
|
235
235
|
def to_page_pdf(self) -> PageDocumentPdf:
|
|
236
236
|
_page = PageDocumentPdf.create_from_page_bytes(
|
|
237
|
-
self.bytes_recognized,
|
|
238
|
-
library
|
|
237
|
+
self.bytes_recognized,
|
|
238
|
+
library=LibraryPDF.FITZ
|
|
239
239
|
)
|
|
240
240
|
return _page
|
|
241
|
-
|
|
241
|
+
|
|
242
242
|
def to_document(self) -> DocumentPdf:
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
243
|
+
return DocumentPdf(pages=[self.to_page_pdf()])
|
|
244
|
+
|
|
245
|
+
def to_dict(
|
|
246
|
+
self,
|
|
247
|
+
separator='\n',
|
|
248
|
+
column_text: ColumnTable.TEXT = ColumnTable.TEXT
|
|
249
|
+
) -> Dict[str, List[str]]:
|
|
250
|
+
#
|
|
251
|
+
image_dict: Dict[str, List[str]] = {
|
|
252
|
+
column_text.value: [],
|
|
253
|
+
ColumnTable.NUMLINHA.value: [],
|
|
250
254
|
}
|
|
251
|
-
image_text:str = self.to_string()
|
|
255
|
+
image_text: str = self.to_string()
|
|
252
256
|
if (image_text is None) or (image_text == ''):
|
|
253
257
|
return {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
+
column_text.value: ['nan'],
|
|
259
|
+
ColumnTable.NUMLINHA.value: ['nan'],
|
|
260
|
+
}
|
|
261
|
+
|
|
258
262
|
image_lines: List[str] = image_text.split(separator)
|
|
259
263
|
for num, line in enumerate(image_lines):
|
|
260
|
-
image_dict[column_text].append(line)
|
|
261
|
-
image_dict[
|
|
262
|
-
return image_dict
|
|
263
|
-
|
|
264
|
-
def to_dataframe(self, separator
|
|
264
|
+
image_dict[column_text.value].append(line)
|
|
265
|
+
image_dict[ColumnTable.NUMLINHA.value].append(f'{num + 1}')
|
|
266
|
+
return image_dict
|
|
267
|
+
|
|
268
|
+
def to_dataframe(self, separator='\n', column_text: ColumnTable.TEXT = ColumnTable.TEXT) -> DataFrame:
|
|
265
269
|
return DataFrame(self.to_dict(separator, column_text))
|
|
266
|
-
|
|
267
|
-
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class BinaryTesseract(object):
|
|
273
|
+
"""
|
|
274
|
+
Fornece o caminho absoluto do tesseract instalado no sistema, se
|
|
275
|
+
disponível. Você pode usar um binário alternativo, basta informar
|
|
276
|
+
o caminho do binário desejado no construtor.
|
|
277
|
+
"""
|
|
278
|
+
_instance = None # Atributo de classe para armazenar a instância singleton
|
|
279
|
+
|
|
280
|
+
def __new__(cls, *args, **kwargs):
|
|
281
|
+
if cls._instance is None:
|
|
282
|
+
cls._instance = super(BinaryTesseract, cls).__new__(cls)
|
|
283
|
+
return cls._instance
|
|
284
|
+
|
|
285
|
+
def __init__(
|
|
286
|
+
self,
|
|
287
|
+
path: File = None, *,
|
|
288
|
+
lang: str = None,
|
|
289
|
+
tess_data_dir: Directory = None
|
|
290
|
+
):
|
|
291
|
+
#
|
|
292
|
+
# Garante que __init__ não será executado mais de uma vez
|
|
293
|
+
if hasattr(self, '_initialized') and self._initialized:
|
|
294
|
+
return
|
|
295
|
+
self._initialized = True
|
|
296
|
+
|
|
297
|
+
self.tess_data_dir: Directory = tess_data_dir
|
|
298
|
+
self.lang: str = lang
|
|
299
|
+
self.path_tesseract: File = path
|
|
300
|
+
if self.path_tesseract is None:
|
|
301
|
+
if KERNEL_TYPE == 'Windows':
|
|
302
|
+
name = 'tesseract.exe'
|
|
303
|
+
else:
|
|
304
|
+
name = 'tesseract'
|
|
305
|
+
output = which(name)
|
|
306
|
+
if output is not None:
|
|
307
|
+
if os.path.isfile(output):
|
|
308
|
+
print(f'[binary]: {output}')
|
|
309
|
+
self.path_tesseract = File(output)
|
|
310
|
+
|
|
311
|
+
def exists(self) -> bool:
|
|
312
|
+
"""Verifica se o binário tesseract existe"""
|
|
313
|
+
if self.path_tesseract is None:
|
|
314
|
+
return False
|
|
315
|
+
return self.path_tesseract.exists()
|
|
316
|
+
|
|
317
|
+
|
|
268
318
|
#======================================================================#
|
|
269
319
|
# Modulo OCR pytesseract
|
|
270
320
|
#======================================================================#
|
|
271
321
|
|
|
272
|
-
|
|
273
|
-
|
|
322
|
+
|
|
323
|
+
class IPytesseract(ABCModuleOcr):
|
|
324
|
+
|
|
325
|
+
def __init__(
|
|
326
|
+
self, *,
|
|
327
|
+
cmd_executable: File,
|
|
328
|
+
lang: str = None,
|
|
329
|
+
tess_data_dir: Directory = None,
|
|
330
|
+
):
|
|
331
|
+
#
|
|
274
332
|
super().__init__(cmd_executable=cmd_executable, lang=lang, tess_data_dir=tess_data_dir)
|
|
275
|
-
self.current_library:LibraryOCR = LibraryOCR.PYTESSERACT
|
|
276
|
-
self._pyTesseract:pytesseract = pytesseract
|
|
333
|
+
self.current_library: LibraryOCR = LibraryOCR.PYTESSERACT
|
|
334
|
+
self._pyTesseract: pytesseract = pytesseract
|
|
277
335
|
self._pyTesseract.tesseract_cmd = self.cmd_executable.absolute()
|
|
278
|
-
|
|
336
|
+
|
|
279
337
|
def __get_tess_dir_config(self) -> str | None:
|
|
280
338
|
"""
|
|
281
339
|
https://github.com/h/pytesseract
|
|
@@ -292,143 +350,142 @@ class IModulePytesseract(ABCModuleOcr):
|
|
|
292
350
|
if not self.tess_data_dir.path.exists():
|
|
293
351
|
return ''
|
|
294
352
|
return r'--tessdata-dir "{}"'.format(self.tess_data_dir.absolute())
|
|
295
|
-
|
|
353
|
+
|
|
296
354
|
def imag_to_string(self, img) -> str:
|
|
297
355
|
if img.current_library == LibraryImage.OPENCV:
|
|
298
|
-
text_img:str = self._pyTesseract.image_to_string(
|
|
356
|
+
text_img: str = self._pyTesseract.image_to_string(
|
|
299
357
|
img.to_image_opencv(),
|
|
300
358
|
lang=self.lang,
|
|
301
359
|
config=self.__get_tess_dir_config()
|
|
302
360
|
)
|
|
303
361
|
else:
|
|
304
|
-
text_img:str = self._pyTesseract.image_to_string(
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
362
|
+
text_img: str = self._pyTesseract.image_to_string(
|
|
363
|
+
img.to_image_pil(),
|
|
364
|
+
lang=self.lang,
|
|
365
|
+
config=self.__get_tess_dir_config()
|
|
366
|
+
)
|
|
309
367
|
return text_img
|
|
310
|
-
|
|
368
|
+
|
|
311
369
|
def image_recognize(self, img) -> TextRecognized:
|
|
370
|
+
"""
|
|
371
|
+
|
|
372
|
+
@rtype: TextRecognized
|
|
373
|
+
"""
|
|
312
374
|
if img.current_library == LibraryImage.OPENCV:
|
|
313
|
-
pdf_bytes:bytes = self._pyTesseract.image_to_pdf_or_hocr(
|
|
375
|
+
pdf_bytes: bytes = self._pyTesseract.image_to_pdf_or_hocr(
|
|
314
376
|
img.to_image_opencv(),
|
|
315
377
|
lang=self.lang,
|
|
316
378
|
config=self.__get_tess_dir_config()
|
|
317
379
|
)
|
|
318
380
|
else:
|
|
319
|
-
pdf_bytes:bytes = self._pyTesseract.image_to_pdf_or_hocr(
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
381
|
+
pdf_bytes: bytes = self._pyTesseract.image_to_pdf_or_hocr(
|
|
382
|
+
img.to_image_pil(),
|
|
383
|
+
lang=self.lang,
|
|
384
|
+
config=self.__get_tess_dir_config()
|
|
385
|
+
)
|
|
324
386
|
return TextRecognized(pdf_bytes)
|
|
325
|
-
|
|
326
|
-
def image_content_data(self, img) -> DataFrame:
|
|
387
|
+
|
|
388
|
+
def image_content_data(self, img: ImageObject) -> DataFrame:
|
|
389
|
+
"""
|
|
390
|
+
Retorna um dataframe gerado por pytesseract
|
|
391
|
+
|
|
392
|
+
@rtype: DataFrame
|
|
393
|
+
"""
|
|
327
394
|
if img.current_library == LibraryImage.OPENCV:
|
|
328
|
-
text_data:DataFrame = self._pyTesseract.image_to_data(
|
|
395
|
+
text_data: DataFrame = self._pyTesseract.image_to_data(
|
|
329
396
|
img.to_image_opencv(),
|
|
330
397
|
lang=self.lang,
|
|
331
398
|
config=self.__get_tess_dir_config(),
|
|
332
399
|
output_type=Output.DATAFRAME,
|
|
333
400
|
)
|
|
334
401
|
else:
|
|
335
|
-
text_data:DataFrame = self._pyTesseract.image_to_data(
|
|
402
|
+
text_data: DataFrame = self._pyTesseract.image_to_data(
|
|
336
403
|
img.to_image_pil(),
|
|
337
404
|
lang=self.lang,
|
|
338
405
|
config=self.__get_tess_dir_config(),
|
|
339
406
|
output_type=Output.DATAFRAME,
|
|
340
407
|
)
|
|
341
408
|
return text_data
|
|
342
|
-
|
|
343
|
-
|
|
409
|
+
|
|
410
|
+
|
|
344
411
|
#======================================================================#
|
|
345
412
|
# Modulo OCR pyocr
|
|
346
413
|
#======================================================================#
|
|
347
414
|
|
|
348
|
-
|
|
349
|
-
|
|
415
|
+
|
|
416
|
+
class IPyOcr(ABCModuleOcr):
|
|
417
|
+
def __init__(self, *, cmd_executable, lang=None, tess_data_dir=None):
|
|
350
418
|
super().__init__(cmd_executable=cmd_executable, lang=lang, tess_data_dir=tess_data_dir)
|
|
351
|
-
self.current_library:LibraryOCR = LibraryOCR.PYOCR
|
|
352
|
-
self.cmd_executable:File = cmd_executable
|
|
353
|
-
self.tess_data_dir:Directory = tess_data_dir
|
|
419
|
+
self.current_library: LibraryOCR = LibraryOCR.PYOCR
|
|
420
|
+
self.cmd_executable: File = cmd_executable
|
|
421
|
+
self.tess_data_dir: Directory = tess_data_dir
|
|
354
422
|
try:
|
|
355
423
|
import pyocr
|
|
356
424
|
import pyocr.tesseract
|
|
357
425
|
except Exception as e:
|
|
358
|
-
raise
|
|
359
|
-
|
|
360
|
-
pyocr_modules:List[ModuleType] = pyocr.get_available_tools()
|
|
426
|
+
raise e
|
|
427
|
+
|
|
428
|
+
pyocr_modules: List[ModuleType] = pyocr.get_available_tools()
|
|
361
429
|
if len(pyocr_modules) == 0:
|
|
362
430
|
raise ValueError(f"{__class__.__name__} No OCR tool found")
|
|
363
431
|
# The tools are returned in the recommended order of usage
|
|
364
|
-
self._pyOcr:pyocr.tesseract = pyocr_modules[0]
|
|
365
|
-
langs:List[str] = self._pyOcr.get_available_languages()
|
|
432
|
+
self._pyOcr: pyocr.tesseract = pyocr_modules[0]
|
|
433
|
+
langs: List[str] = self._pyOcr.get_available_languages()
|
|
366
434
|
if lang in lang:
|
|
367
435
|
self.lang = lang
|
|
368
436
|
else:
|
|
369
437
|
self.lang = langs[0]
|
|
370
|
-
|
|
438
|
+
|
|
371
439
|
# Ex: Will use tool 'libtesseract'
|
|
372
440
|
print(f"Will use tool {self._pyOcr.get_name()}")
|
|
373
|
-
|
|
441
|
+
|
|
374
442
|
def imag_to_string(self, img) -> str:
|
|
375
443
|
return self._pyOcr.image_to_string(
|
|
376
444
|
img.to_image_pil(),
|
|
377
445
|
lang=self.lang,
|
|
378
446
|
builder=pyocr.builders.TextBuilder()
|
|
379
447
|
)
|
|
380
|
-
|
|
448
|
+
|
|
381
449
|
def image_recognize(self, img) -> TextRecognized:
|
|
382
450
|
raise NotImplementedError(f'{__class__.__name__} método não implementado')
|
|
383
|
-
|
|
451
|
+
|
|
384
452
|
def image_content_data(self, img) -> DataFrame:
|
|
385
453
|
raise NotImplementedError(f'{__class__.__name__} método não implementado')
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
class ModuleOcr(
|
|
389
|
-
def __init__(self, module_ocr:
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
lang=module_ocr.lang,
|
|
393
|
-
tess_data_dir=module_ocr.tess_data_dir
|
|
394
|
-
)
|
|
395
|
-
self.module_ocr:ABCModuleOcr = module_ocr
|
|
396
|
-
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
class ModuleOcr(object):
|
|
457
|
+
def __init__(self, module_ocr: IPytesseract | IPyOcr):
|
|
458
|
+
self.module_ocr: IPytesseract | IPyOcr = module_ocr
|
|
459
|
+
|
|
397
460
|
def image_content_data(self, img: ImageObject) -> DataFrame:
|
|
398
461
|
return self.module_ocr.image_content_data(img)
|
|
399
|
-
|
|
400
|
-
def image_recognize(self, img:ImageObject) -> TextRecognized:
|
|
462
|
+
|
|
463
|
+
def image_recognize(self, img: ImageObject) -> TextRecognized:
|
|
401
464
|
return self.module_ocr.image_recognize(img)
|
|
402
|
-
|
|
465
|
+
|
|
403
466
|
def imag_to_string(self, img) -> str:
|
|
404
467
|
return self.module_ocr.imag_to_string(img)
|
|
405
|
-
|
|
468
|
+
|
|
406
469
|
@classmethod
|
|
407
470
|
def create(
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
tess_data_dir = None
|
|
414
|
-
) -> ModuleOcr:
|
|
471
|
+
cls,
|
|
472
|
+
library_ocr=LibraryOCR.PYTESSERACT,
|
|
473
|
+
*,
|
|
474
|
+
binary_tess: BinaryTesseract = BinaryTesseract(),
|
|
475
|
+
) -> ModuleOcr:
|
|
415
476
|
#
|
|
416
477
|
if library_ocr == LibraryOCR.PYTESSERACT:
|
|
417
|
-
_module_ocr =
|
|
478
|
+
_module_ocr = IPytesseract(
|
|
479
|
+
cmd_executable=binary_tess.path_tesseract,
|
|
480
|
+
lang=binary_tess.lang,
|
|
481
|
+
tess_data_dir=binary_tess.tess_data_dir,
|
|
482
|
+
)
|
|
418
483
|
elif library_ocr == LibraryOCR.PYOCR:
|
|
419
|
-
_module_ocr =
|
|
484
|
+
_module_ocr = IPyOcr(
|
|
485
|
+
cmd_executable=binary_tess.path_tesseract,
|
|
486
|
+
lang=binary_tess.lang,
|
|
487
|
+
tess_data_dir=binary_tess.tess_data_dir,
|
|
488
|
+
)
|
|
420
489
|
else:
|
|
421
490
|
raise NotImplementedError(f'{__class__.__name__}\nLibraryOcr não implementada: {library_ocr}')
|
|
422
491
|
return cls(_module_ocr)
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
#
|
|
3
|
+
from pandas import DataFrame
|
|
4
|
+
from soup_files import (
|
|
5
|
+
File, Directory, UserAppDir, UserFileSystem,
|
|
6
|
+
InputFiles, JsonConvert, JsonData, LibraryDocs,
|
|
7
|
+
KERNEL_TYPE,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
from convert_stream import (
|
|
11
|
+
LibraryDates, LibraryImage, LibraryPDF, LibImageToPDF, LibConvertPDF,
|
|
12
|
+
ImageObject, PdfStream, ImageStream, PageDocumentPdf, DocumentPdf,
|
|
13
|
+
ArrayString, DataString, print_line, print_title, FileToTable,
|
|
14
|
+
)
|
|
15
|
+
from convert_stream.models import ConvertStringDate
|
|
16
|
+
from convert_stream.table_files import ColumnTable
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ocr_stream
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4
|
|
4
4
|
Summary: Extrair textos de documentos digitalizados e imagens.
|
|
5
5
|
Author: Bruno Chaves
|
|
6
6
|
Requires: PyPDF2
|
|
@@ -17,14 +17,14 @@ Requires: soup_files
|
|
|
17
17
|
Requires: convert_stream
|
|
18
18
|
Requires-Python: >=3.11
|
|
19
19
|
Description-Content-Type: text/markdown
|
|
20
|
-
Requires-Dist:
|
|
21
|
-
Requires-Dist:
|
|
22
|
-
Requires-Dist:
|
|
23
|
-
Requires-Dist:
|
|
24
|
-
Requires-Dist:
|
|
25
|
-
Requires-Dist:
|
|
26
|
-
Requires-Dist: opencv-python
|
|
27
|
-
Requires-Dist: convert_stream
|
|
20
|
+
Requires-Dist: PyMuPDF
|
|
21
|
+
Requires-Dist: reportlab
|
|
22
|
+
Requires-Dist: openpyxl
|
|
23
|
+
Requires-Dist: pandas
|
|
24
|
+
Requires-Dist: Pillow>=11.3.0
|
|
25
|
+
Requires-Dist: requests>=2.32.4
|
|
26
|
+
Requires-Dist: opencv-python
|
|
27
|
+
Requires-Dist: convert_stream>=1.4
|
|
28
28
|
Requires-Dist: soup_files
|
|
29
29
|
Dynamic: requires
|
|
30
30
|
|
|
@@ -4,23 +4,24 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ocr_stream"
|
|
7
|
-
version = "1.
|
|
7
|
+
version = "1.4"
|
|
8
8
|
authors = [
|
|
9
9
|
{ name="Bruno Chaves"},
|
|
10
10
|
]
|
|
11
|
+
|
|
11
12
|
description = "Extrair textos de documentos digitalizados e imagens."
|
|
12
13
|
readme = "README.md"
|
|
13
14
|
requires-python = ">=3.11"
|
|
14
15
|
|
|
15
16
|
dependencies = [
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"opencv-python
|
|
23
|
-
"convert_stream",
|
|
17
|
+
"PyMuPDF",
|
|
18
|
+
"reportlab",
|
|
19
|
+
"openpyxl",
|
|
20
|
+
"pandas",
|
|
21
|
+
"Pillow>=11.3.0",
|
|
22
|
+
"requests>=2.32.4",
|
|
23
|
+
"opencv-python",
|
|
24
|
+
"convert_stream>=1.4",
|
|
24
25
|
"soup_files",
|
|
25
26
|
]
|
|
26
27
|
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
from ocr_stream.utils import (
|
|
4
|
-
File, Directory, ImageObject,
|
|
5
|
-
DataFrame, PageDocumentPdf,
|
|
6
|
-
DocumentPdf, PdfStream, LibraryPDF,
|
|
7
|
-
)
|
|
8
|
-
from ocr_stream.models import ABCRecognizeImage, LibraryOCR
|
|
9
|
-
from ocr_stream.modules_ocr import ModuleOcr, TextRecognized
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class RecognizeImage(ABCRecognizeImage):
|
|
13
|
-
def __init__(self, module_ocr):
|
|
14
|
-
super().__init__(module_ocr)
|
|
15
|
-
|
|
16
|
-
def image_content_data(self, img: ImageObject | File) -> DataFrame:
|
|
17
|
-
if isinstance(img, File):
|
|
18
|
-
return self.module_ocr.image_content_data(ImageObject.create_from_file(img))
|
|
19
|
-
elif isinstance(img, ImageObject):
|
|
20
|
-
return self.module_ocr.image_content_data(img)
|
|
21
|
-
else:
|
|
22
|
-
raise ValueError(f'{__class__.__name__}\nUse: ImageObject() ou File(), não {type(img)}')
|
|
23
|
-
|
|
24
|
-
def image_recognize(self, img: ImageObject | File) -> TextRecognized:
|
|
25
|
-
if isinstance(img, File):
|
|
26
|
-
return self.module_ocr.image_recognize(ImageObject.create_from_file(img))
|
|
27
|
-
elif isinstance(img, ImageObject):
|
|
28
|
-
return self.module_ocr.image_recognize(img)
|
|
29
|
-
else:
|
|
30
|
-
raise ValueError(f'{__class__.__name__}\nUse: ImageObject() ou File(), não {type(img)}')
|
|
31
|
-
|
|
32
|
-
def image_to_string(self, img: ImageObject | File) -> str:
|
|
33
|
-
if isinstance(img, File):
|
|
34
|
-
return self.module_ocr.imag_to_string(ImageObject.create_from_file(img))
|
|
35
|
-
elif isinstance(img, ImageObject):
|
|
36
|
-
return self.module_ocr.imag_to_string(img)
|
|
37
|
-
else:
|
|
38
|
-
raise ValueError(f'{__class__.__name__}\nUse: ImageObject() ou File(), não {type(img)}')
|
|
39
|
-
|
|
40
|
-
@classmethod
|
|
41
|
-
def create(
|
|
42
|
-
cls,
|
|
43
|
-
library_ocr = LibraryOCR.PYTESSERACT,
|
|
44
|
-
*,
|
|
45
|
-
path_tesseract,
|
|
46
|
-
lang=None,
|
|
47
|
-
tess_data_dir=None
|
|
48
|
-
) -> RecognizeImage:
|
|
49
|
-
#
|
|
50
|
-
module_ocr: ModuleOcr = ModuleOcr.create(
|
|
51
|
-
library_ocr,
|
|
52
|
-
path_tesseract=path_tesseract,
|
|
53
|
-
lang=lang,
|
|
54
|
-
tess_data_dir=tess_data_dir
|
|
55
|
-
)
|
|
56
|
-
return cls(module_ocr)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class RecognizePdf(object):
|
|
60
|
-
def __init__(self, recognize_image: RecognizeImage):
|
|
61
|
-
self.recognize_image: RecognizeImage = recognize_image
|
|
62
|
-
|
|
63
|
-
def recognize_page_pdf(self, page:PageDocumentPdf) -> PageDocumentPdf:
|
|
64
|
-
"""
|
|
65
|
-
Converte a página em Imagem, reconhece o texto com OCR e
|
|
66
|
-
retorna uma nova página com o texto reconhecido.
|
|
67
|
-
"""
|
|
68
|
-
pdf_stream = PdfStream(library_pdf=LibraryPDF.FITZ)
|
|
69
|
-
pdf_stream.add_page(page)
|
|
70
|
-
img: ImageObject = pdf_stream.to_images()[0]
|
|
71
|
-
text_recognized:TextRecognized = self.recognize_image.image_recognize(img)
|
|
72
|
-
return text_recognized.to_page_pdf()
|
|
73
|
-
|
|
74
|
-
def recognize_document(self, doc:DocumentPdf) -> DocumentPdf:
|
|
75
|
-
new: DocumentPdf = DocumentPdf()
|
|
76
|
-
for page in doc.pages:
|
|
77
|
-
recognized_page: PageDocumentPdf = self.recognize_page_pdf(page)
|
|
78
|
-
new.add_page(recognized_page)
|
|
79
|
-
return new
|
|
80
|
-
|
|
81
|
-
@classmethod
|
|
82
|
-
def create(
|
|
83
|
-
cls,
|
|
84
|
-
library_ocr = LibraryOCR.PYTESSERACT,
|
|
85
|
-
*,
|
|
86
|
-
path_tesseract: File,
|
|
87
|
-
lang:str=None,
|
|
88
|
-
tess_data_dir: Directory=None,
|
|
89
|
-
) -> RecognizePdf:
|
|
90
|
-
#
|
|
91
|
-
#
|
|
92
|
-
recognize_image = RecognizeImage.create(
|
|
93
|
-
library_ocr,
|
|
94
|
-
path_tesseract=path_tesseract,
|
|
95
|
-
lang=lang,
|
|
96
|
-
tess_data_dir=tess_data_dir
|
|
97
|
-
)
|
|
98
|
-
return cls(recognize_image)
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
@@ -1,39 +0,0 @@
|
|
|
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
|
-
|
|
@@ -1,13 +0,0 @@
|
|
|
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
|
-
)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|