2014-02-13 105 views
5

我想在python中使用Tesseract 3.02與ctypes和cv2。正方體提供了一個DLL暴露集合C風格的API,其中之一是如下:在python中使用tesseract 3.02與ctypes和cv2的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中找不到任何地方。我不確定我在這裏做錯了什麼。

我找到類似的問題How to recognize data not filename using ctypes and tesseract 3.0.2?,但問題沒有解決。 我也知道https://code.google.com/p/python-tesseract/,我深入瞭解這個項目的源代碼,但是無法找到我需要的信息。

我可以通過調用cv2.imshow來確認test.bmp中的圖像是否合法並可讀。 同樣的圖像可以通過命令行上的Tesseract進行OCR。

+1

我不能幫你用C-API,但如果沒有人回答:使用[可執行程序獲得出文本](https://github.com/niccokunzmann/mousemove/blob/master/mousemove/auslesen.py#L32)。它遠離最佳狀態。 – User

+1

'TessBaseAPISetImage'不返回值。默認的'restype'是'c_int',所以44只是垃圾轉換爲整數。 – eryksun

回答

9

默認restypec_int,並且整數的默認參數轉換也是c_int。您將在網絡上找到假設具有sizeof(int) == sizeof(void *)的32位平臺的示例。這從來都不是一個好的假設。爲了保護64位指針在與Python整數轉換時截斷,設置函數指針的argtypesrestype。無論如何,這是一個好主意,因爲它允許ctypes在使用錯誤類型或數量的參數時引發ArgumentError

如果您不想爲每個函數定義原型,那麼至少應將TessBaseAPICreate.restype設置爲不透明指針類型。

以下ctypes定義基於標頭api/capi.h。爲了方便起見,我將API打包爲Tesseract類。

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() 

我libtesseract.so.3測試這在Linux。請注意0​​返回一個NumPy數組。這有一個​​屬性,其中包括_as_parameter_鉤子,設置爲指向該陣列的c_void_p指針。還要注意,問題中顯示的代碼具有寬度和高度轉置。它應該是h, w, d = imcv.shape

ocrtest.png:

ocrtest

輸出:

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: 
+0

非常感謝@eryksun!我在交互式shell中測試的事實誤導了我(它返回了44,這讓我想到了函數導致的錯誤) – xbtsw

+0

我偶然發現了谷歌搜索,並且有同樣的問題。但是,我對這個答案感到困惑。這段代碼後面的代碼片段是基於頭文件api/capi.h.'做了什麼?是否需要將cv2圖像傳遞給c api?或者唯一需要的是'Example(用libtesseract.so.3在Linux上測試)'後的代碼片段? – Anthony

+0

@Anthony,我重寫了更多面向對象的答案,並且我更新了github上新項目站點的標題鏈接。 – eryksun

相關問題