2014-02-13 10 views
5

Ich versuche Tesseract 3.02 mit Ctypes und Cv2 in Python zu verwenden. Tesseract stellt eine DLL ausgesetzt Satz von C-Stil-APIs, einer von ihnen, wie folgend:C-API von Tesseract 3.02 mit Ctypes und Cv2 in Python verwenden

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

Bisher mein Code wie folgt:

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 

Die letzte Zeile einen Fehlercode 44 zurückgeben, was ich nirgends in errcode.h von Tesseract finden kann. Ich bin mir nicht sicher, was ich hier falsch mache.

Ich habe ähnliche Frage How to recognize data not filename using ctypes and tesseract 3.0.2? gefunden, aber die Frage ist nicht gelöst. Ich bin mir auch bewusst, https://code.google.com/p/python-tesseract/, ich graben in Quellcode dieses Projekts, aber nicht in der Lage, die Informationen zu finden, die ich brauche.

Ich kann das Bild in test.bmp ist legitim und lesbar durch den Aufruf cv2.imshow bestätigen. auch das gleiche Bild kann OCR von Tesseract auf der Kommandozeile sein.

+1

Ich kann nicht Sie mit dem C-Api helfen, aber wenn niemand antwortet: Verwenden Sie die [ausführbare Dateien zu erhalten aus dem Text] (https://github.com/niccokunzmann/mousemove/blob/master/mousemove/auslesen.py#L32). Es ist weit weg von optimal. – User

+1

'TessBaseAPISetImage' gibt keinen Wert zurück. Der Standard-'restype' ist' c_int', also wird 44 nur in eine ganze Zahl umgewandelt. – eryksun

Antwort

9

Der Standardwert restype ist c_int, und die Standardargumentkonvertierung von einer ganzen Zahl ist ebenfalls c_int. Im Web finden Sie Beispiele, die von einer 32-Bit-Plattform mit sizeof(int) == sizeof(void *) ausgehen. Dies war nie eine gute Annahme zu machen. Um einen 64-Bit-Zeiger vor dem Trunkieren zu schützen, wenn er in und aus einer Python-Ganzzahl konvertiert wird, setzen Sie den Funktionszeiger auf argtypes und restype. Es ist eine gute Idee, dies trotzdem zu tun, da es ctypes erlaubt, einen ArgumentError zu erzeugen, wenn die falschen Typen oder die Anzahl der Argumente verwendet werden.

Wenn Sie die Prototypen nicht für jede Funktion definieren möchten, setzen Sie mindestens TessBaseAPICreate.restype auf einen undurchsichtigen Zeigertyp. Die folgenden Ctypes-Definitionen basieren auf der Kopfzeile api/capi.h. Aus praktischen Gründen habe ich die API in eine Klasse verpackt.

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

Beispiel Nutzung:

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

ich dies mit libtesseract.so.3 auf Linux getestet. Beachten Sie, dass cv2.imread ein NumPy-Array zurückgibt. Dies hat ein ctypes Attribut, das den _as_parameter_ Hook enthält, als c_void_p Zeiger auf das Array festgelegt. Beachten Sie auch, dass der Code in der Frage die Breite und Höhe transponiert hat. Es sollte h, w, d = imcv.shape sein.

ocrtest.png:

ocrtest

Ausgang:

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

Vielen Dank @eryksksun!Die Tatsache, dass ich in interaktiver Shell getestet habe, täuscht mich (es gab 44 zurück, was mich denken lässt, dass die Funktion Fehler ergab) – xbtsw

+0

Ich stolperte hier von Google-Suche und habe die gleiche Frage. Ich bin jedoch von dieser Antwort verwirrt. Was bedeutet das Snippet nach der Zeile? Das folgende basiert auf dem Header api/capi.h. Ist das nötig, um ein cv2-Bild an die cpi zu übergeben? Oder das einzige Erforderliche wäre das Snippet nach 'Beispiel (getestet unter Linux mit libtesseract.so.3)'? – Anthony

+0

@Anthony, schrieb ich die Antwort um mehr objektorientiert, und ich aktualisierte den Header-Link auf die neue Projektseite auf GitHub. – eryksun