在python中使用tesseract 3.02的C API与ctypes和cv2

2024-04-25

我正在尝试在 python 中将 Tesseract 3.02 与 ctypes 和 cv2 一起使用。 Tesseract 提供了一组公开的 DLL C 风格 API,其中之一如下:

TESS_API void  TESS_CALL TessBaseAPISetImage(TessBaseAPI* handle, const unsigned char* imagedata, int width, int height, int bytes_per_pixel, int bytes_per_line);

到目前为止,我的代码如下:

tesseract = ctypes.cdll.LoadLibrary('libtesseract302.dll')
api = tesseract.TessBaseAPICreate()
tesseract.TessBaseAPIInit3(api, '', 'eng')
imcv = cv2.imread('test.bmp')
w, h, d = imcv.shape
ret = tesseract.TessBaseAPISetImage(api, ctypes.c_char_p(str(imcv.data)), w, h, d, w * d)
#ret = 44 here

最后一行返回错误代码 44,我在 Tesseract 提供的 errcode.h 中找不到该代码。我不确定我在这里做错了什么。

我发现了类似的问题如何使用 ctypes 和 tesseract 3.0.2 识别数据而不是文件名? https://stackoverflow.com/questions/13150937/how-to-recognize-data-not-filename-using-ctypes-and-tesseract-3-0-2,但是问题并没有解决。 我也知道https://code.google.com/p/python-tesseract/ https://code.google.com/p/python-tesseract/,我深入研究了这个项目的源代码,但无法找到我需要的信息。

我可以通过调用确认 test.bmp 中的图像是合法且可读的cv2.imshow。 同样的图像也可以通过 Tesseract 在命令行上进行 OCR。


默认restype is c_int,并且从整数的默认参数转换也是c_int。您会在网络上找到假设 32 位平台具有以下功能的示例:sizeof(int) == sizeof(void *)。这从来都不是一个好的假设。要保护 64 位指针在与 Python 整数相互转换时不被截断,请设置函数指针的argtypes and restype。无论如何,这样做是个好主意,因为它允许 ctypes 提出ArgumentError当使用错误的类型或数量的参数时。

如果您不想为每个函数定义原型,那么至少设置TessBaseAPICreate.restype到不透明的指针类型。

以下ctypes定义基于标头api/capi.h https://github.com/tesseract-ocr/tesseract/blob/3.02.02/api/capi.h。为了方便起见,我将 API 打包成Tesseract class.

import sys
import cv2
import ctypes
import ctypes.util

if sys.platform == 'win32':
    LIBNAME = 'libtesseract302'
else:
    LIBNAME = 'tesseract'

class TesseractError(Exception):
    pass

class Tesseract(object):
    _lib = None
    _api = None

    class TessBaseAPI(ctypes._Pointer):
        _type_ = type('_TessBaseAPI', (ctypes.Structure,), {})

    @classmethod
    def setup_lib(cls, lib_path=None):
        if cls._lib is not None:
            return
        if lib_path is None:
            lib_path = ctypes.util.find_library(LIBNAME)
            if lib_path is None:
                 raise TesseractError('tesseract library not found')
        cls._lib = lib = ctypes.CDLL(lib_path)

        # source:
        # https://github.com/tesseract-ocr/tesseract/
        #         blob/3.02.02/api/capi.h

        lib.TessBaseAPICreate.restype = cls.TessBaseAPI

        lib.TessBaseAPIDelete.restype = None # void
        lib.TessBaseAPIDelete.argtypes = (
            cls.TessBaseAPI,) # handle

        lib.TessBaseAPIInit3.argtypes = (
            cls.TessBaseAPI, # handle
            ctypes.c_char_p, # datapath
            ctypes.c_char_p) # language

        lib.TessBaseAPISetImage.restype = None
        lib.TessBaseAPISetImage.argtypes = (
            cls.TessBaseAPI, # handle
            ctypes.c_void_p, # imagedata
            ctypes.c_int,    # width
            ctypes.c_int,    # height
            ctypes.c_int,    # bytes_per_pixel
            ctypes.c_int)    # bytes_per_line

        lib.TessBaseAPIGetUTF8Text.restype = ctypes.c_char_p
        lib.TessBaseAPIGetUTF8Text.argtypes = (
            cls.TessBaseAPI,) # handle

    def __init__(self, language='eng', datapath=None, lib_path=None):
        if self._lib is None:
            self.setup_lib(lib_path)
        self._api = self._lib.TessBaseAPICreate()
        if self._lib.TessBaseAPIInit3(self._api, datapath, language):
            raise TesseractError('initialization failed')

    def __del__(self):
        if not self._lib or not self._api:
            return
        if not getattr(self, 'closed', False):
            self._lib.TessBaseAPIDelete(self._api)
            self.closed = True

    def _check_setup(self):
        if not self._lib:
            raise TesseractError('lib not configured')
        if not self._api:
            raise TesseractError('api not created')

    def set_image(self, imagedata, width, height,
                  bytes_per_pixel, bytes_per_line=None):
        self._check_setup()
        if bytes_per_line is None:
            bytes_per_line = width * bytes_per_pixel
        self._lib.TessBaseAPISetImage(self._api,
                                      imagedata, width, height,
                                      bytes_per_pixel, bytes_per_line)

    def get_utf8_text(self):
        self._check_setup()
        return self._lib.TessBaseAPIGetUTF8Text(self._api)

    def get_text(self):
        self._check_setup()
        result = self._lib.TessBaseAPIGetUTF8Text(self._api)
        if result:
            return result.decode('utf-8')

用法示例:

if __name__ == '__main__':
    imcv = cv2.imread('ocrtest.png')
    height, width, depth = imcv.shape

    tess = Tesseract()
    tess.set_image(imcv.ctypes, width, height, depth)
    text = tess.get_text()

    print text.strip()

我在 Linux 上使用 libtesseract.so.3 对此进行了测试。注意cv2.imread返回一个 NumPy 数组。这有一个ctypes属性包括_as_parameter_钩子,设置为c_void_p指向数组的指针。另请注意,问题中显示的代码已转换宽度和高度。本来应该是h, w, d = imcv.shape.

ocrtest.png:

Output:

I am trying to use Tesseract 3.02 with ctypes and cv2 in python. Tesseract
provides a DLL exposed set of C style APIs, one of them is as following:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在python中使用tesseract 3.02的C API与ctypes和cv2 的相关文章

随机推荐