編寫Tesseract的Python擴展


Tesseract是一個開源的OCR(光學字符識別)引擎,用於識別並輸出圖片中的文字。雖然和商業軟件比起來識別精度不算很高,但是如果你要尋找免費開源的OCR引擎,可能Tesseract就是唯一的選擇了。Tesseract用起來還算是比較方便。它提供了一個簡單的命令行工具,沒有很多選項,輸入圖片輸出就是文字。因為是開源的,你也可以直接編譯使用它基於C++的庫。

最近一段時間我對Python產生了很大的興趣。它是如此的簡潔高效,只要可以用Python完成的工作就懶得使用其他編程語言。所以到了應用Tesseract的時候我首先想到了去Google一下有沒有Python binding。確實有人使用swig做了個tesseract的封裝,不過不幸的是實際應用存在不少問題。首先是安裝不便,尤其在mac上的安裝令人崩潰。即使完成安裝,不知為何又segment fault。其次,很多方法只做了簡單的封裝,又缺乏文檔,想做深入一點的應用例如輸出文字在圖中的位置,感覺無從着手。不如從Tesseract的源代碼入手,自己編寫python的擴展,對tesseract的某些感興趣的方法做個封裝,也順便熟悉下Python和C/C++集成的方法。可以在擴展里為所欲為,真是令人心情愉快。

首先,新建一個cpp源文件,然后為這個新模塊想個名字,比如 tessex。然后,需要定義這個新模塊,以及模塊里需要暴露出來的方法。這樣在Python里就可以用import tessex來載入模塊。

static PyMethodDef tessexMethods[] = {
        {"recognize", (PyCFunction)tessex_recognize,
                METH_VARARGS|METH_KEYWORDS,
                "recognize text in an image."},
        {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC inittessex(void) {
    (void) Py_InitModule("tessex", tessexMethods);
}

這里,我們暴露一個方法recognize,用來掃描給定圖片然后返回識別的文字以及位置。大家知道Python方法可以傳兩種參數,一種是無名的,一種是有名的,分別對應METH_VARARGS以及METH_KEYWORDS。作為一個有點完美主義傾向的人,我把兩個選項都勾上了。然后我們看下recognize方法的定義。正如之前講的,需要聲明參數args以及kw。

static PyObject* tessex_recognize(PyObject* self, PyObject* args, PyObject* kw){

接下來是展開從Python調用傳進來的參數。要使用有名參數,需要把所有參數名都先列出來。

  static const char* kwlist[]={"data", "w", "h", "channels", "step", NULL};

然后調用PyArg_ParseTupleAndKeywords展開有名參數。一個格式字符串用於聲明參數的類型。data是圖像的像素buffer,適用S類型。w、h、channels、step分別是圖像的寬度、高度、信道數、步長,都是整型變量,適用i類型。

    PyStringObject *data;
    int w=0;
    int h=0;
    int channels=0;
    int step=0;

    if (!PyArg_ParseTupleAndKeywords(args, kw, "Siiii", (char**)(kwlist),
            &data, &w, &h, &channels, &step)) {
        PyErr_SetString(PyExc_Exception, "Tessex: Failed to parse arguments.");
        return NULL;
    }
 
        

我們要開始使用Tesseract的API了。Tesseract支持多種語言,不過語言包要分別下載安裝。這里我們使用英語。 

    tesseract::TessBaseAPI *api = new tesseract::TessBaseAPI();
    if (api->Init(NULL, "eng")) {
        PyErr_SetString(PyExc_Exception, "Tessex: Failed to initialize tesseract API.");
        return NULL;
    }

 把傳入的圖像數據傳遞給Tesseract,然后進行識別。

    api->SetImage((const unsigned char*)PyString_AS_STRING(data),
            w, h, channels, step);

    api->Recognize(0);

識別結果的處理稍微復雜點。一般的應用如果只想得到所有文字,只要調用GetUTF8Text()就完了。但是我想知道每一行的文字,它們的具體位置以及可信度,就需要對識別結果進行詳細的分析。幸運的是Tesseract提供了iterator接口,可以返回不同粒度的數據。這里我選擇了按行輸出,即RIL_TEXTLINE。 

    PyObject* l = PyList_New(0);
    tesseract::ResultIterator* it = api->GetIterator();
    it->Begin();
    while(1) {
        char* utf8_text;
        int left, top, right, bottom;
        int confidence = 0;

        utf8_text = it->GetUTF8Text(tesseract::RIL_TEXTLINE);
        if (utf8_text == NULL)
            break;

        confidence = it->Confidence(tesseract::RIL_TEXTLINE);
        it->BoundingBox(tesseract::RIL_TEXTLINE, &left, &top, &right, &bottom);

        PyObject* t = Py_BuildValue("(siiiii)", utf8_text,
                left, top, right, bottom, confidence);
        PyList_Append(l, t);

        delete []utf8_text;

        it->Next(tesseract::RIL_TEXTLINE);
    }
    api->End();

    PyObject* o = Py_BuildValue("O", l);

    return o;

返回的是一個list,其每個元素都是一個tuple,代表識別出來的文字行,包括文字、位置和可信度。

最后不要忘了include需要的頭文件,並在鏈接選項里加入需要的庫。

#include "Python.h"
#include <tesseract/baseapi.h>
#include <tesseract/resultiterator.h>

具體如何編譯tesseract可以參考https://code.google.com/p/tesseract-ocr/wiki/Compiling/ 

在示例代碼里我們並沒有用到任何圖形庫。但是因為要使用Tesseract就必須鏈接leptonica庫,所以需要加入鏈接選項-llept。

如果你想在擴展里使用leptonica的功能可以include <leptonica/allheaders.h>。或者你想使用openCV,可以include <opencv2/opencv.hpp>並鏈接-lopencv_XXXXX。

 

這樣代碼部分算是完成了。不過接下來還有一步,我們需要打包完成一個Python擴展使之容易編譯和安裝。可以使用distutils模塊。

from distutils.core import setup, Extension

tessenigma = Extension (
    'tessex', 
    sources=['tessex.cpp'],
        include_dirs = ['/usr/local/include'],
    libraries=[ 'tesseract'], 
    library_dirs=['/usr/local/lib']
)

setup (name='tessex', 
    version='1.0',
    description='This is a tesseract extensiion.',
    ext_modules = [tessex])

把這些定義寫入一個setup.py文件里。這樣我們就可以用通常的方式編譯和安裝模塊了。編譯用setup.py build。一個動態鏈接庫會生成。例如在Linux下面就是tessex.so。安裝模塊使用setup.py install。前面生成的庫文件會被復制到Python的site-packages下面。當然你也可以手動復制到$PYTHONPATH路徑下面,一樣能被Python找到。

 

安裝好擴展后,在Python里是這樣調用的,假定我們使用一個openCV圖像:

import tessex
import cv

cv_img = cv.LoadImage(path, cv.CV_LOAD_IMAGE_COLOR)

lines = tessex.recognize( data=cv_img.tostring(), w=cv_img.width, h=cv_img.height, channels=cv_img.nChannels, step=cv_img.width * cv_img.nChannels * cv_img.depth / 8) for line in lines:   line_text, left, top, right, bottom, confidence = line

通過Tesseract擴展,可以在Python中比較方便地識別圖像中的文字以及位置,對基於圖像識別的自動化測試是很有幫助的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM