├── .gitignore ├── README.txt ├── setup.py ├── test ├── ocr_test.py └── receipt.png ├── tightocr.egg-info ├── PKG-INFO ├── SOURCES.txt ├── dependency_links.txt ├── entry_points.txt ├── top_level.txt └── zip-safe └── tightocr ├── __init__.py ├── adapters ├── __init__.py ├── api_adapter.py └── lept_adapter.py ├── calls ├── __init__.py ├── api_calls.py └── lept_calls.py ├── constants.py ├── library_ctess.py ├── library_lept.py └── types.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | /build 3 | /dist 4 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | Introduction 2 | ============ 3 | 4 | TightOCR provides a thin library to provide an efficient, pleasant, Pythonic 5 | interface to Tesseract. Tesseract (https://code.google.com/p/tesseract-ocr/) 6 | is the world's most universal OCR project, owned by Google. 7 | 8 | The primary goals of this implementation is to provide 9 | the following functionalities to Python: 10 | 11 | > OCR a document and return a block of text. 12 | > OCR a document, and identify the various parts of a document to allow an 13 | application to take advantage of Tesseract's layout analysis. 14 | 15 | Secondary functions that are available: 16 | 17 | > Confidence of recognition 18 | > HTML-formatted output 19 | > Slope and margin of text 20 | 21 | Though I have tried to provide access to as many of the API methods as 22 | possible, there is a very limited amount of documentation available, so many 23 | of the more exotic functions haven't been properly tested. IF YOU WANT TO HELP 24 | WITH THIS, JUST DO IT AND REGISTER ISSUES OR SUBMIT PULL-REQUESTS. 25 | 26 | 27 | This library was built as an alternative to python-tesseract 28 | (http://code.google.com/p/python-tesseract) for the following reasons: 29 | 30 | > The usage of SWIG produces an implementation that is excessive and 31 | burdensome. 32 | > python-tesseract is, ironically, incomplete. You are unable to enumerate the 33 | parts of the document (getIterator() is broken: 34 | http://code.google.com/p/python-tesseract/issues/detail?id=50&can=4&sort=-id) 35 | 36 | 37 | Requirements 38 | ============ 39 | 40 | CTesseract (https://github.com/dsoprea/CTesseract) 41 | Leptonica (http://code.google.com/p/leptonica/) 42 | 43 | 44 | Installation 45 | ============ 46 | 47 | The Leptonica and CTesseract shared-libraries (liblept.so, 48 | libctesseract.so) must be findable. 49 | 50 | 51 | Usage 52 | ===== 53 | 54 | Return the whole document as text: 55 | 56 | from tightocr.adapters.api_adapter import TessApi 57 | from tightocr.adapters.lept_adapter import pix_read 58 | 59 | t = TessApi(None, 'eng'); 60 | 61 | p = pix_read('receipt.png') 62 | t.set_image_pix(p) 63 | 64 | t.recognize() 65 | if t.mean_text_confidence() < 85: 66 | raise Exception("Too much error.") 67 | 68 | print(t.get_utf8_text()) 69 | 70 | Enumerate individual blocks of text (referred to as "paragraphs"), driven by 71 | the document's layout: 72 | 73 | from tightocr.adapters.api_adapter import TessApi 74 | from tightocr.adapters.lept_adapter import pix_read 75 | from tightocr.constants import RIL_PARA 76 | 77 | t = TessApi(None, 'eng'); 78 | p = pix_read('receipt.png') 79 | t.set_image_pix(p) 80 | t.recognize() 81 | 82 | if t.mean_text_confidence() < 85: 83 | raise Exception("Too much error.") 84 | 85 | for block in t.iterate(RIL_PARA): 86 | print block 87 | 88 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from sys import exit 2 | 3 | from setuptools import setup, find_packages 4 | from setuptools.command.install import install 5 | 6 | def pre_install(): 7 | print("Checking for libctesseract.") 8 | 9 | try: 10 | from tightocr import library_ctess 11 | except: 12 | print("The libctesseract shared-library could not be found/imported.") 13 | exit(1) 14 | 15 | print("Checking for liblept.") 16 | 17 | try: 18 | from tightocr import library_lept 19 | except: 20 | print("The liblept shared-library could not be found/imported.") 21 | exit(1) 22 | 23 | class custom_install(install): 24 | def run(self): 25 | pre_install() 26 | install.run(self) 27 | 28 | long_description = "A thin (non-SWiG) wrapper for Tesseract OCR using "\ 29 | "CTesseract." 30 | 31 | setup(name='tightocr', 32 | version='0.4.4', 33 | description="Thin and pleasant wrapper for Tesseract OCR.", 34 | long_description=long_description, 35 | classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers 36 | keywords='ocr tesseract ctesseract', 37 | author='Dustin Oprea', 38 | author_email='myselfasunder@gmail.com', 39 | url='https://github.com/dsoprea/TightOCR', 40 | license='GPL 2', 41 | packages=find_packages(exclude=['ez_setup', 'examples', 'tests']), 42 | include_package_data=True, 43 | zip_safe=True, 44 | install_requires=[], 45 | cmdclass={ 'install': custom_install }, 46 | ) 47 | -------------------------------------------------------------------------------- /test/ocr_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python2.7 2 | 3 | import sys 4 | sys.path.insert(0, '..') 5 | 6 | import os 7 | import logging 8 | 9 | os.environ['DYLD_LIBRARY_PATH'] = '/usr/local/Cellar/tesseract/3.02.02/lib:/Users/dustin/development/cpp/ctesseract/build' 10 | 11 | from tightocr.adapters.api_adapter import TessApi 12 | from tightocr.adapters.lept_adapter import pix_read 13 | from tightocr.constants import RIL_PARA 14 | 15 | def configure_logging(): 16 | logger = logging.getLogger() 17 | logger.setLevel(logging.DEBUG) 18 | 19 | # create console handler and set level to debug 20 | ch = logging.StreamHandler() 21 | 22 | # create formatter 23 | formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 24 | 25 | # add formatter to ch 26 | ch.setFormatter(formatter) 27 | 28 | # add ch to logger 29 | logger.addHandler(ch) 30 | 31 | configure_logging() 32 | 33 | t = TessApi(None, 'eng'); 34 | 35 | t.set_variable('tessedit_char_whitelist', '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\'".,;?!/\\$-()&%@') 36 | 37 | p = pix_read('receipt.png') 38 | t.set_image_pix(p) 39 | t.recognize() 40 | 41 | confidence = t.mean_text_confidence() 42 | if confidence < 60: 43 | raise Exception("Too much error: %d" % (confidence)) 44 | 45 | for block in t.iterate(RIL_PARA): 46 | print(block) 47 | 48 | # direction = t.get_text_direction() 49 | # print(t.get_hocr_text(1)) 50 | # print(t.get_utf8_text()) 51 | -------------------------------------------------------------------------------- /test/receipt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dsoprea/TightOCR/c23b4235d922c1f487244ad53d45f0ff9a5d088c/test/receipt.png -------------------------------------------------------------------------------- /tightocr.egg-info/PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 1.0 2 | Name: tightocr 3 | Version: 0.4.3 4 | Summary: Thin and pleasant wrapper for Tesseract OCR. 5 | Home-page: https://github.com/dsoprea/TightOCR 6 | Author: Dustin Oprea 7 | Author-email: myselfasunder@gmail.com 8 | License: GPL 2 9 | Description: A thin (non-SWiG) wrapper for Tesseract OCR using CTesseract. 10 | Keywords: ocr tesseract ctesseract 11 | Platform: UNKNOWN 12 | -------------------------------------------------------------------------------- /tightocr.egg-info/SOURCES.txt: -------------------------------------------------------------------------------- 1 | README.txt 2 | setup.py 3 | tightocr/__init__.py 4 | tightocr/constants.py 5 | tightocr/library_ctess.py 6 | tightocr/library_lept.py 7 | tightocr/types.py 8 | tightocr.egg-info/PKG-INFO 9 | tightocr.egg-info/SOURCES.txt 10 | tightocr.egg-info/dependency_links.txt 11 | tightocr.egg-info/entry_points.txt 12 | tightocr.egg-info/top_level.txt 13 | tightocr.egg-info/zip-safe 14 | tightocr/adapters/__init__.py 15 | tightocr/adapters/api_adapter.py 16 | tightocr/adapters/lept_adapter.py 17 | tightocr/calls/__init__.py 18 | tightocr/calls/api_calls.py 19 | tightocr/calls/lept_calls.py -------------------------------------------------------------------------------- /tightocr.egg-info/dependency_links.txt: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tightocr.egg-info/entry_points.txt: -------------------------------------------------------------------------------- 1 | 2 | # -*- Entry points: -*- 3 | -------------------------------------------------------------------------------- /tightocr.egg-info/top_level.txt: -------------------------------------------------------------------------------- 1 | tightocr 2 | -------------------------------------------------------------------------------- /tightocr.egg-info/zip-safe: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /tightocr/__init__.py: -------------------------------------------------------------------------------- 1 | class LibraryReturnError(ValueError): 2 | pass 3 | 4 | def simple_nonzero_result_checker(value): 5 | if value != 0: 6 | raise LibraryReturnError("Library function returned failure (%d)." % 7 | (value)) 8 | 9 | return value 10 | 11 | def simple_more_than_zero_result_checker(value): 12 | if value < 0: 13 | raise LibraryReturnError("Library function returned failure (%d)." % 14 | (value)) 15 | 16 | return value 17 | 18 | def simple_ptr_result_checker(value): 19 | if value is None: 20 | raise LibraryReturnError("Library function returned failure (NULL).") 21 | 22 | return value 23 | 24 | def simple_boolean_error_checker(value): 25 | if value == 0: 26 | raise LibraryReturnError("Library function returned failure (0).") 27 | 28 | return value 29 | 30 | -------------------------------------------------------------------------------- /tightocr/adapters/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dsoprea/TightOCR/c23b4235d922c1f487244ad53d45f0ff9a5d088c/tightocr/adapters/__init__.py -------------------------------------------------------------------------------- /tightocr/adapters/api_adapter.py: -------------------------------------------------------------------------------- 1 | from ctypes import byref, c_bool, c_int, byref, POINTER 2 | 3 | from tightocr import types, simple_ptr_result_checker, \ 4 | simple_boolean_error_checker 5 | 6 | from tightocr.types import TessMrIterator 7 | from tightocr.calls.api_calls import * 8 | 9 | 10 | class _TextWrapper(object): 11 | def __init__(self, text_void_ptr): 12 | self.__text_ptr = c_char_p(text_void_ptr) 13 | 14 | def __del__(self): 15 | c_tess_delete_string(self.__text_ptr) 16 | 17 | def __str__(self): 18 | return self.__text_ptr.value 19 | 20 | def _tess_mr_it_get_utf8_text(mr_iterator_p, level): 21 | text = c_tess_mr_it_get_utf8_text(mr_iterator_p, level) 22 | if text is None: 23 | raise ValueError("Could not retrieve text from MR iterator.") 24 | 25 | return text 26 | 27 | 28 | class TessApi(object): 29 | def __init__(self, data_path, language): 30 | assert(language is not None) 31 | 32 | api = types.TessApi() 33 | 34 | # The result is automatically checked. 35 | c_tess_create(data_path, language, byref(api)) 36 | 37 | self.__api = api 38 | 39 | def __del__(self): 40 | c_tess_destroy(byref(self.__api)) 41 | 42 | @classmethod 43 | def version(cls): 44 | return c_tess_version() 45 | 46 | def get_init_languages_as_string(self): 47 | str_ = c_tess_get_init_languages_as_string(byref(self.__api)) 48 | 49 | simple_ptr_result_checker(str_) 50 | return str_ 51 | 52 | @classmethod 53 | def make_tess_ocr_row(cls, baseline, xheight, descender, ascender): 54 | 55 | result = TessRow() 56 | c_tess_make_tess_ocr_row(baseline, 57 | xheight, 58 | descender, 59 | ascender, 60 | byref(result)) 61 | 62 | return result 63 | 64 | @classmethod 65 | def make_tblob(cls, pix): 66 | result = TessBlob() 67 | c_tess_make_tblob(byref(result), byref(result)) 68 | 69 | return result 70 | 71 | @classmethod 72 | def delete_block_list(cls, blocks): 73 | c_tess_delete_block_list(byref(blocks)) 74 | 75 | def iterate(self, level): 76 | mr_iterator = TessMrIterator() 77 | c_tess_get_iterator(byref(self.__api), byref(mr_iterator)) 78 | 79 | try: 80 | while 1: 81 | result = c_tess_mr_it_empty(byref(mr_iterator), level) 82 | if result == 0: 83 | text_ptr = _tess_mr_it_get_utf8_text(byref(mr_iterator), level) 84 | yield _TextWrapper(text_ptr) 85 | 86 | result = c_tess_mr_it_next(byref(mr_iterator), level) 87 | if result == 0: 88 | break 89 | finally: 90 | c_tess_mr_it_delete(byref(mr_iterator)) 91 | 92 | def init_lang_mod(self, data_path, language): 93 | c_tess_init_lang_mod(byref(self.__api), data_path, language) 94 | 95 | def set_page_seg_mode(self, mode): 96 | c_tess_set_page_seg_mode(byref(self.__api), mode) 97 | 98 | def get_page_seg_mode(self): 99 | return c_tess_get_page_seg_mode(byref(self.__api)) 100 | 101 | def clear_adaptive_classifier(self): 102 | c_tess_clear_adaptive_classifier(byref(self.__api)) 103 | 104 | def set_image_pix(self, pix): 105 | c_tess_set_image_pix(byref(self.__api), pix) 106 | 107 | def set_source_resolution(self, ppi): 108 | c_tess_set_source_resolution(byref(self.__api), ppi) 109 | 110 | def set_rectangle(self, left, top, width, height): 111 | c_tess_set_rectangle(byref(self.__api), left, top, width, height) 112 | 113 | def get_thresholded_image(self): 114 | return c_tess_get_thresholded_image(byref(self.__api)) 115 | 116 | def get_regions(self, return_pixa=False): 117 | if return_pixa is True: 118 | pixa_p = PixaP() 119 | pixa_p_parm = byref(pixa_p) 120 | else: 121 | pixa_p = None 122 | pixa_p_parm = None 123 | 124 | boxa_p = c_tess_get_regions(byref(self.__api), pixa_p_parm) 125 | 126 | simple_ptr_result_checker(boxa_p) 127 | # TODO: Wrap results to be freed. 128 | return (boxa_p, pixa_p) 129 | 130 | def get_text_lines(self, return_pixa=False, return_block_ids=False): 131 | 132 | if return_pixa is True: 133 | pixa_p = TessPixaP() 134 | pixa_p_parm = byref(pixa_p) 135 | else: 136 | pixa_p = None 137 | pixa_p_parm = None 138 | 139 | if return_block_ids is True: 140 | block_ids_p = POINTER(c_int)() 141 | block_ids_p_parm = byref(block_ids_p) 142 | else: 143 | block_ids_p = None 144 | block_ids_p_parm = None 145 | 146 | block_ids_p = POINTER(c_int)() 147 | boxa_p = c_tess_get_text_lines(byref(self.__api), 148 | pixa_p_parm, 149 | block_ids_p_parm) 150 | 151 | simple_ptr_result_checker(boxa_p) 152 | # TODO: Wrap results to be freed. 153 | return (boxa_p, pixa_p, block_ids_p) 154 | 155 | def get_strips(self, return_pixa=False, return_block_ids=False): 156 | 157 | if return_pixa is True: 158 | pixa_p = TessPixaP() 159 | pixa_p_parm = byref(pixa_p) 160 | else: 161 | pixa_p = None 162 | pixa_p_parm = None 163 | 164 | if return_block_ids is True: 165 | block_ids_p = POINTER(c_int)() 166 | block_ids_p_parm = byref(block_ids_p) 167 | else: 168 | block_ids_p = None 169 | block_ids_p_parm = None 170 | 171 | boxa_p = c_tess_get_strips(byref(self.__api), 172 | pixa_p_parm, 173 | block_ids_parm) 174 | 175 | simple_ptr_result_checker(boxa_p) 176 | # TODO: Wrap results to be freed. 177 | return (boxa_p, pixa_p, block_ids_p) 178 | 179 | def get_words(self, return_pixa=False): 180 | 181 | if return_pixa is True: 182 | pixa_p = PixaP() 183 | pixa_p_parm = byref(pixa_p) 184 | else: 185 | pixa_p = None 186 | pixa_p_parm = None 187 | 188 | boxa_p = c_tess_get_words(byref(self.__api), pixa_p_parm) 189 | 190 | simple_ptr_result_checker(boxa_p) 191 | # TODO: Wrap results to be freed. 192 | return (boxa_p, pixa_p) 193 | 194 | def get_connected_components(self, return_pixa=False): 195 | if return_pixa is True: 196 | pixa_p = PixaP() 197 | pixa_p_parm = byref(pixa_p) 198 | else: 199 | pixa_p = None 200 | pixa_p_parm = None 201 | 202 | boxa_p = c_tess_get_connected_components(byref(self.__api), 203 | pixa_p_parm) 204 | 205 | simple_ptr_result_checker(boxa_p) 206 | # TODO: Wrap results to be freed. 207 | return (boxa_p, pixa_p) 208 | 209 | def get_component_images(self, level, text_only_int, return_pixa=False, 210 | return_block_ids=False): 211 | 212 | if return_pixa is True: 213 | pixa_p = TessPixaP() 214 | pixa_p_parm = byref(pixa_p) 215 | else: 216 | pixa_p = None 217 | pixa_p_parm = None 218 | 219 | if return_block_ids is True: 220 | block_ids_p = POINTER(c_int)() 221 | block_ids_p_parm = byref(block_ids_p) 222 | else: 223 | block_ids_p = None 224 | block_ids_p_parm = None 225 | 226 | boxa_p = c_tess_get_component_images(byref(self.__api), 227 | level, 228 | bool(text_only_int), 229 | pixa_p_parm, 230 | block_ids_p_parm) 231 | 232 | simple_ptr_result_checker(boxa_p) 233 | # TODO: Wrap results to be freed. 234 | return (boxa_p, pixa_p, block_ids_p) 235 | 236 | def get_thresholded_image_scale_factor(self): 237 | return c_tess_get_thresholded_image_scale_factor(byref(self.__api)) 238 | 239 | def dump_pgm(self, filename): 240 | c_tess_dump_pgm(byref(self.__api), filename) 241 | 242 | def analyse_layout(self): 243 | page_it = TessPageIterator() 244 | c_tess_analyse_layout(byref(self.__api), byref(page_it)) 245 | return page_it 246 | 247 | def recognize(self): 248 | c_tess_recognize(byref(self.__api)) 249 | 250 | def process_pages_string(self, filename, retry_config, timeout_millisec): 251 | text_out = TessString() 252 | result = c_tess_process_pages_string(filename, retry_config, 253 | timeout_millisec, byref(text_out)) 254 | if result == 0: 255 | raise ValueError("process_pages_string failed.") 256 | 257 | return str_out 258 | 259 | def process_page_string(self, pix, page_index, filename, retry_config, 260 | timeout_millisec): 261 | 262 | text_out = TessString() 263 | c_tess_process_page_string(byref(self.__api), pix, page_index, 264 | filename, retry_config, timeout_millisec, 265 | byref(text_out)) 266 | 267 | return text_out 268 | 269 | def get_iterator(self): 270 | mr_iterator = TessMrIterator() 271 | c_tess_get_iterator(byref(self.__api), byref(mr_iterator)) 272 | return mr_iterator 273 | 274 | def get_utf8_text(self): 275 | str_ = c_tess_get_utf8_text(byref(self.__api)) 276 | simple_ptr_result_checker(str_) 277 | return _TextWrapper(str_) 278 | 279 | def get_hocr_text(self, page_number): 280 | str_ = c_tess_get_hocr_text(byref(self.__api), page_number) 281 | simple_ptr_result_checker(str_) 282 | return str_ 283 | 284 | def get_box_text(self, page_number): 285 | str_ = c_tess_get_box_text(byref(self.__api), page_number) 286 | simple_ptr_result_checker(str_) 287 | return str_ 288 | 289 | def get_unlv_text(self): 290 | str_ = c_tess_get_unlv_text(byref(self.__api), page_number) 291 | simple_ptr_result_checker(str_) 292 | return str_ 293 | 294 | def mean_text_confidence(self): 295 | return c_tess_mean_text_conf(byref(self.__api)) 296 | 297 | def all_word_confidences(self): 298 | # TODO: Post-process result. 299 | return c_tess_all_word_confidences(byref(self.__api)) 300 | 301 | def adapt_to_word_str(self, mode, word_string): 302 | return c_tess_adapt_to_word_str(byref(self.__api), mode, word_string) 303 | 304 | def clear(self): 305 | c_tess_clear(byref(self.__api)) 306 | 307 | def is_valid_word(self, word): 308 | is_valid = c_tess_is_valid_word(byref(self.__api), word) 309 | return bool(is_valid) 310 | 311 | def get_text_direction(self): 312 | offset = c_int() 313 | slope = c_float() 314 | 315 | result = c_tess_get_text_direction(byref(self.__api), 316 | byref(offset), 317 | byref(slope)) 318 | 319 | simple_boolean_error_checker(result) 320 | return (offset, slope) 321 | 322 | def find_row_for_box(self, block_list, left, top, right, 323 | bottom): 324 | 325 | row = TessRow() 326 | c_tess_find_row_for_box(byref(self.__api), 327 | block_list, 328 | left, 329 | top, 330 | right, 331 | bottom, 332 | byref(row)) 333 | 334 | return row 335 | 336 | def get_unichar(self, unichar_id): 337 | str_ = c_tess_get_unichar(byref(self.__api), unichar_id) 338 | 339 | simple_ptr_result_checker(str_) 340 | return str_ 341 | 342 | def set_min_orientation_margin(self, margin): 343 | c_tess_set_min_orientation_margin(byref(self.__api), margin) 344 | 345 | def get_block_text_orientations(self): 346 | 347 | block_orientation = POINTER(c_int)() 348 | vertifcal_writing = POINTER(c_bool)() 349 | 350 | c_tess_get_block_text_orientations(byref(self.__api), 351 | byref(block_orientation), 352 | vertical_writing) 353 | # TODO: Needs to be freed. 354 | return (block_orientation, vertical_writing) 355 | 356 | def find_lines_create_block_list(self): 357 | result = TessBlockList() 358 | c_tess_find_lines_create_block_list(byref(self.__api), byref(result)) 359 | return result 360 | 361 | def set_variable(self, name, value): 362 | c_tess_set_variable(byref(self.__api), c_char_p(name), c_char_p(value)) 363 | -------------------------------------------------------------------------------- /tightocr/adapters/lept_adapter.py: -------------------------------------------------------------------------------- 1 | from tightocr.calls.lept_calls import c_lept_pix_read 2 | from tightocr.types import TessPixP 3 | from tightocr import simple_ptr_result_checker 4 | 5 | def pix_read(file_path): 6 | pix_p = c_lept_pix_read(file_path) 7 | simple_ptr_result_checker(pix_p) 8 | 9 | return pix_p 10 | 11 | -------------------------------------------------------------------------------- /tightocr/calls/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dsoprea/TightOCR/c23b4235d922c1f487244ad53d45f0ff9a5d088c/tightocr/calls/__init__.py -------------------------------------------------------------------------------- /tightocr/calls/api_calls.py: -------------------------------------------------------------------------------- 1 | from ctypes import POINTER, c_int, c_char_p, c_void_p, c_ubyte, c_float, \ 2 | c_double 3 | 4 | from tightocr.library_ctess import libctess 5 | from tightocr.types import TessApiP, TessPixaP, TessPixP, TessBoxaP, \ 6 | TessPageIteratorP, TessMrIteratorP, TessStringP, \ 7 | TessBlockListP, TessRowP, TessBlobP, TessMrIteratorP 8 | 9 | from tightocr import simple_nonzero_result_checker, \ 10 | simple_more_than_zero_result_checker 11 | 12 | c_tess_create = libctess.tess_create 13 | c_tess_create.argtypes = [c_char_p, c_char_p, TessApiP] 14 | c_tess_create.restype = simple_nonzero_result_checker 15 | 16 | c_tess_destroy = libctess.tess_destroy 17 | c_tess_destroy.argtypes = [TessApiP] 18 | c_tess_destroy.restype = simple_nonzero_result_checker 19 | 20 | c_tess_version = libctess.tess_version 21 | c_tess_version.argtypes = [] 22 | c_tess_version.restype = c_char_p 23 | 24 | c_tess_get_init_languages_as_string = \ 25 | libctess.tess_get_init_languages_as_string 26 | c_tess_get_init_languages_as_string.argtypes = [TessApiP] 27 | c_tess_get_init_languages_as_string.restype = c_char_p 28 | 29 | c_tess_init_lang_mod = libctess.tess_init_lang_mod 30 | c_tess_init_lang_mod.argtypes = [TessApiP, c_char_p, c_char_p] 31 | c_tess_init_lang_mod.restype = simple_nonzero_result_checker 32 | 33 | c_tess_set_page_seg_mode = libctess.tess_set_page_seg_mode 34 | c_tess_set_page_seg_mode.argtypes = [TessApiP, c_int] 35 | c_tess_set_page_seg_mode.restype = simple_nonzero_result_checker 36 | 37 | c_tess_get_page_seg_mode = libctess.tess_get_page_seg_mode 38 | c_tess_get_page_seg_mode.argtypes = [TessApiP] 39 | c_tess_get_page_seg_mode.restype = simple_nonzero_result_checker 40 | 41 | #c_tess_tesseract_rect = libctess.tess_tesseract_rect 42 | #c_tess_tesseract_rect.argtypes = [TessApiP, POINTER(c_ubyte), c_int, c_int, 43 | # c_int, c_int, c_int, c_int] 44 | #c_tess_tesseract_rect.restype = c_char_p 45 | 46 | c_tess_clear_adaptive_classifier = libctess.tess_clear_adaptive_classifier 47 | c_tess_clear_adaptive_classifier.argtypes = [TessApiP] 48 | c_tess_clear_adaptive_classifier.restype = simple_nonzero_result_checker 49 | 50 | #c_tess_set_image_details = libctess.tess_set_image_details 51 | #c_tess_set_image_details.argtypes = [TessApiP, POINTER(c_ubyte), c_int, c_int, 52 | # c_int, c_int] 53 | #c_tess_set_image_details.restype = simple_nonzero_result_checker 54 | 55 | c_tess_set_image_pix = libctess.tess_set_image_pix 56 | c_tess_set_image_pix.argtypes = [TessApiP, TessPixP] 57 | c_tess_set_image_pix.restype = simple_nonzero_result_checker 58 | 59 | c_tess_set_source_resolution = libctess.tess_set_source_resolution 60 | c_tess_set_source_resolution.argtypes = [TessApiP, c_int] 61 | c_tess_set_source_resolution.restype = simple_nonzero_result_checker 62 | 63 | c_tess_set_rectangle = libctess.tess_set_rectangle 64 | c_tess_set_rectangle.argtypes = [TessApiP, c_int, c_int, c_int, c_int] 65 | c_tess_set_rectangle.restype = simple_nonzero_result_checker 66 | 67 | c_tess_get_thresholded_image = libctess.tess_get_thresholded_image 68 | c_tess_get_thresholded_image.argtypes = [TessApiP] 69 | c_tess_get_thresholded_image.restype = TessPixaP 70 | 71 | c_tess_get_regions = libctess.tess_get_regions 72 | c_tess_get_regions.argtypes = [TessApiP, POINTER(TessPixaP)] 73 | c_tess_get_regions.restype = TessBoxaP 74 | 75 | c_tess_get_text_lines = libctess.tess_get_text_lines 76 | c_tess_get_text_lines.argtypes = [TessApiP, 77 | POINTER(TessPixaP), 78 | POINTER(POINTER(c_int))] 79 | c_tess_get_text_lines.restype = TessBoxaP 80 | 81 | c_tess_get_strips = libctess.tess_get_strips 82 | c_tess_get_strips.argtypes = [TessApiP, 83 | POINTER(TessPixaP), 84 | POINTER(POINTER(c_int))] 85 | c_tess_get_strips.restype = TessBoxaP 86 | 87 | c_tess_get_words = libctess.tess_get_words 88 | c_tess_get_words.argtypes = [TessApiP, POINTER(TessPixaP)] 89 | c_tess_get_words.restype = TessBoxaP 90 | 91 | c_tess_get_connected_components = libctess.tess_get_connected_components 92 | c_tess_get_connected_components.argtypes = [TessApiP, POINTER(TessPixaP)] 93 | c_tess_get_connected_components.restype = TessBoxaP 94 | 95 | c_tess_get_component_images = libctess.tess_get_component_images 96 | c_tess_get_component_images.argtypes = [TessApiP, 97 | c_int, 98 | c_int, 99 | POINTER(TessPixaP), 100 | POINTER(POINTER(c_int))] 101 | c_tess_get_component_images.restype = TessBoxaP 102 | 103 | c_tess_get_thresholded_image_scale_factor = \ 104 | libctess.tess_get_thresholded_image_scale_factor 105 | c_tess_get_thresholded_image_scale_factor.argtypes = [TessApiP] 106 | c_tess_get_thresholded_image_scale_factor.restype = simple_nonzero_result_checker 107 | 108 | c_tess_dump_pgm = libctess.tess_dump_pgm 109 | c_tess_dump_pgm.argtypes = [TessApiP, c_char_p] 110 | c_tess_dump_pgm.restype = simple_nonzero_result_checker 111 | 112 | c_tess_analyse_layout = libctess.tess_analyse_layout 113 | c_tess_analyse_layout.argtypes = [TessApiP, TessPageIteratorP] 114 | c_tess_analyse_layout.restype = simple_nonzero_result_checker 115 | 116 | c_tess_recognize = libctess.tess_recognize 117 | c_tess_recognize.argtypes = [TessApiP] 118 | c_tess_recognize.restype = simple_nonzero_result_checker 119 | 120 | c_tess_process_pages_string = libctess.tess_process_pages_string 121 | c_tess_process_pages_string.argtypes = [TessApiP, c_char_p, c_char_p, c_int, 122 | TessStringP] 123 | c_tess_process_pages_string.restype = c_int 124 | 125 | c_tess_process_page_string = libctess.tess_process_page_string 126 | c_tess_process_page_string.argtypes = [TessApiP, 127 | TessPixP, 128 | c_int, 129 | c_char_p, 130 | c_char_p, 131 | c_int, 132 | TessStringP] 133 | c_tess_process_page_string.restype = c_int 134 | 135 | c_tess_get_iterator = libctess.tess_get_iterator 136 | c_tess_get_iterator.argtypes = [TessApiP, TessMrIteratorP] 137 | c_tess_get_iterator.restype = simple_nonzero_result_checker 138 | 139 | c_tess_get_utf8_text = libctess.tess_get_utf8_text 140 | c_tess_get_utf8_text.argtypes = [TessApiP] 141 | c_tess_get_utf8_text.restype = c_void_p 142 | 143 | c_tess_get_hocr_text = libctess.tess_get_hocr_text 144 | c_tess_get_hocr_text.argtypes = [TessApiP, c_int] 145 | c_tess_get_hocr_text.restype = c_char_p 146 | 147 | c_tess_get_box_text = libctess.tess_get_box_text 148 | c_tess_get_box_text.argtypes = [TessApiP, c_int] 149 | c_tess_get_box_text.restype = c_char_p 150 | 151 | c_tess_get_unlv_text = libctess.tess_get_unlv_text 152 | c_tess_get_unlv_text.argtypes = [TessApiP] 153 | c_tess_get_unlv_text.restype = c_char_p 154 | 155 | c_tess_mean_text_conf = libctess.tess_mean_text_conf 156 | c_tess_mean_text_conf.argtypes = [TessApiP] 157 | c_tess_mean_text_conf.restype = c_int 158 | 159 | c_tess_all_word_confidences = libctess.tess_all_word_confidences 160 | c_tess_all_word_confidences.argtypes = [TessApiP] 161 | c_tess_all_word_confidences.restype = POINTER(c_int) 162 | 163 | c_tess_adapt_to_word_str = libctess.tess_adapt_to_word_str 164 | c_tess_adapt_to_word_str.argtypes = [TessApiP, c_int, c_char_p] 165 | c_tess_adapt_to_word_str.restype = c_int 166 | 167 | c_tess_clear = libctess.tess_clear 168 | c_tess_clear.argtypes = [TessApiP] 169 | c_tess_clear.restype = simple_nonzero_result_checker 170 | 171 | c_tess_is_valid_word = libctess.tess_is_valid_word 172 | c_tess_is_valid_word.argtypes = [TessApiP, c_char_p] 173 | c_tess_is_valid_word.restype = c_int 174 | 175 | c_tess_get_text_direction = libctess.tess_get_text_direction 176 | c_tess_get_text_direction.argtypes = [TessApiP, 177 | POINTER(c_int), 178 | POINTER(c_float)] 179 | c_tess_get_text_direction.restype = c_int 180 | 181 | c_tess_find_row_for_box = libctess.tess_find_row_for_box 182 | c_tess_find_row_for_box.argtypes = [TessApiP, 183 | TessBlockListP, 184 | c_int, 185 | c_int, 186 | c_int, 187 | c_int, 188 | TessRowP] 189 | c_tess_find_row_for_box.restype = simple_nonzero_result_checker 190 | 191 | c_tess_get_unichar = libctess.tess_get_unichar 192 | c_tess_get_unichar.argtypes = [TessApiP, c_int] 193 | c_tess_get_unichar.restype = c_char_p 194 | 195 | c_tess_make_tess_ocr_row = libctess.tess_make_tess_ocr_row 196 | c_tess_make_tess_ocr_row.argtypes = [c_float, 197 | c_float, 198 | c_float, 199 | c_float, 200 | TessRowP] 201 | c_tess_make_tess_ocr_row.restype = simple_nonzero_result_checker 202 | 203 | c_tess_make_tblob = libctess.tess_make_tblob 204 | c_tess_make_tblob.argtypes = [TessPixP, TessBlobP] 205 | c_tess_make_tblob.restype = simple_nonzero_result_checker 206 | 207 | c_tess_set_min_orientation_margin = libctess.tess_set_min_orientation_margin 208 | c_tess_set_min_orientation_margin.argtypes = [TessApiP, c_double] 209 | c_tess_set_min_orientation_margin.restype = simple_nonzero_result_checker 210 | 211 | c_tess_get_block_text_orientations = libctess.tess_get_block_text_orientations 212 | c_tess_get_block_text_orientations.argtypes = [TessApiP, 213 | POINTER(POINTER(c_int)), 214 | POINTER(c_void_p), 215 | POINTER(c_int)] 216 | c_tess_get_block_text_orientations.restype = simple_nonzero_result_checker 217 | 218 | c_tess_find_lines_create_block_list = \ 219 | libctess.tess_find_lines_create_block_list 220 | c_tess_find_lines_create_block_list.argtypes = [TessApiP, TessBlockListP] 221 | c_tess_find_lines_create_block_list.restype = simple_nonzero_result_checker 222 | 223 | c_tess_delete_block_list = libctess.tess_delete_block_list 224 | c_tess_delete_block_list.argtypes = [TessBlockListP] 225 | c_tess_delete_block_list.restype = simple_nonzero_result_checker 226 | 227 | c_tess_delete_string = libctess.tess_delete_string 228 | c_tess_delete_string.argtypes = [c_char_p] 229 | c_tess_delete_string.restype = simple_nonzero_result_checker 230 | 231 | # Handler for MR iterator. 232 | 233 | c_tess_mr_it_next = libctess.tess_mr_it_next 234 | c_tess_mr_it_next.argtypes = [TessMrIteratorP, c_int] 235 | c_tess_mr_it_next.restype = simple_more_than_zero_result_checker 236 | 237 | c_tess_mr_it_get_utf8_text = libctess.tess_mr_it_get_utf8_text 238 | c_tess_mr_it_get_utf8_text.argtypes = [TessMrIteratorP, c_int] 239 | c_tess_mr_it_get_utf8_text.restype = c_void_p 240 | 241 | c_tess_mr_it_delete = libctess.tess_mr_it_delete 242 | c_tess_mr_it_delete.argtypes = [TessMrIteratorP] 243 | c_tess_mr_it_delete.restype = simple_nonzero_result_checker 244 | 245 | c_tess_mr_it_empty = libctess.tess_mr_it_empty 246 | c_tess_mr_it_empty.argtypes = [TessMrIteratorP, c_int] 247 | c_tess_mr_it_empty.restype = simple_more_than_zero_result_checker 248 | 249 | c_tess_set_variable = libctess.tess_set_variable 250 | c_tess_set_variable.argtypes = [TessApiP, c_char_p, c_char_p] 251 | c_tess_set_variable.restype = simple_nonzero_result_checker 252 | -------------------------------------------------------------------------------- /tightocr/calls/lept_calls.py: -------------------------------------------------------------------------------- 1 | from ctypes import c_char_p 2 | 3 | from tightocr.library_lept import liblept 4 | from tightocr.types import TessPixP 5 | 6 | c_lept_pix_read = liblept.pixRead 7 | c_lept_pix_read.argtypes = [c_char_p] 8 | c_lept_pix_read.restype = TessPixP 9 | 10 | -------------------------------------------------------------------------------- /tightocr/constants.py: -------------------------------------------------------------------------------- 1 | # enum PageIteratorLevel { 2 | RIL_BLOCK = 0 # Block of text/image/separator line. 3 | RIL_PARA = 1 # Paragraph within a block. 4 | RIL_TEXTLINE = 2 # Line within a paragraph. 5 | RIL_WORD = 3 # Word within a textline. 6 | RIL_SYMBOL = 4 # Symbol/character within a word. 7 | 8 | -------------------------------------------------------------------------------- /tightocr/library_ctess.py: -------------------------------------------------------------------------------- 1 | from ctypes import cdll 2 | from ctypes.util import find_library 3 | 4 | _TESS_FILEPATH = find_library('ctesseract') 5 | if _TESS_FILEPATH is None: 6 | _TESS_FILEPATH = 'libctesseract.so' 7 | 8 | libctess = cdll.LoadLibrary(_TESS_FILEPATH) 9 | 10 | -------------------------------------------------------------------------------- /tightocr/library_lept.py: -------------------------------------------------------------------------------- 1 | from ctypes import cdll 2 | from ctypes.util import find_library 3 | 4 | _LEPT_FILEPATH = find_library('lept') 5 | if _LEPT_FILEPATH is None: 6 | _LEPT_FILEPATH = 'liblept.so' 7 | 8 | liblept = cdll.LoadLibrary(_LEPT_FILEPATH) 9 | 10 | -------------------------------------------------------------------------------- /tightocr/types.py: -------------------------------------------------------------------------------- 1 | from ctypes import Structure, POINTER, c_void_p, c_int 2 | 3 | class TessApi(Structure): 4 | _fields_ = [('opaque', c_void_p)] 5 | 6 | TessApiP = POINTER(TessApi) 7 | 8 | class TessPix(Structure): 9 | # TODO: Finish. 10 | _fields_ = [] 11 | 12 | TessPixP = POINTER(TessPix) 13 | 14 | class TessPixa(Structure): 15 | # TODO: Finish. 16 | _fields_ = [] 17 | 18 | TessPixaP = POINTER(TessPixa) 19 | 20 | class TessBoxa(Structure): 21 | # TODO: Finish. 22 | _fields_ = [] 23 | 24 | TessBoxaP = POINTER(TessBoxa) 25 | 26 | class TessPageIterator(Structure): 27 | # TODO: Finish. 28 | _fields_ = [] 29 | 30 | TessPageIteratorP = POINTER(TessPageIterator) 31 | 32 | class TessMrIterator(Structure): 33 | # TODO: Finish. 34 | _fields_ = [] 35 | 36 | TessMrIteratorP = POINTER(TessMrIterator) 37 | 38 | class TessString(Structure): 39 | # TODO: Finish. 40 | _fields_ = [] 41 | 42 | TessStringP = POINTER(TessString) 43 | 44 | class TessBlockList(Structure): 45 | # TODO: Finish. 46 | _fields_ = [] 47 | 48 | TessBlockListP = POINTER(TessBlockList) 49 | 50 | class TessRow(Structure): 51 | # TODO: Finish. 52 | _fields_ = [] 53 | 54 | TessRowP = POINTER(TessRow) 55 | 56 | class TessBlob(Structure): 57 | # TODO: Finish. 58 | _fields_ = [] 59 | 60 | TessBlobP = POINTER(TessBlob) 61 | 62 | class TessMrIterator(Structure): 63 | # TODO: Finish. 64 | _fields_ = [('iterator', c_void_p), 65 | ('type', c_int)] 66 | 67 | TessMrIteratorP = POINTER(TessMrIterator) 68 | 69 | --------------------------------------------------------------------------------