将cv::Mat转换为tesseract

converting cv::Mat for tesseract

本文关键字:tesseract 转换 Mat cv      更新时间:2023-10-16

我使用OpenCV来提取扫描文档的子图像,并希望使用tesseract对该子图像执行OCR。

我发现我可以在tesseract中使用两种方法进行文本识别,但到目前为止,我无法找到一个有效的解决方案。

a。)如何将cv::Mat转换为PIX* ?(PIX*是leptonica的数据类型)

根据下面的vasiles代码,这基本上是我当前的代码:

 cv::Mat image = cv::imread("c:/image.png"); 
 cv::Mat subImage = image(cv::Rect(50, 200, 300, 100)); 
 int depth;
 if(subImage.depth() == CV_8U)
    depth = 8;
 //other cases not considered yet
 PIX* pix = pixCreateHeader(subImage.size().width, subImage.size().height, depth);
 pix->data = (l_uint32*) subImage.data; 
 tesseract::TessBaseAPI tess;
 STRING text; 
 if(tess.ProcessPage(pix, 0, 0, &text))
 {
    std::cout << text.string(); 
 }   

虽然它没有崩溃或任何东西,OCR结果仍然是错误的。它应该能识别示例图像中的一个单词,但它返回了一些不可读的字符。

方法PIX_HEADER不存在,所以我用pixCreateHeader,但它不以通道数作为参数。那么我如何设置频道的数量呢?

b)如何使用cv::Mat代替TesseractRect()

Tesseract提供了另一种文本识别方法,使用以下签名:

char * TessBaseAPI::TesseractRect   (   
    const UINT8 *   imagedata,
    int     bytes_per_pixel,
    int     bytes_per_line,
    int     left,
    int     top,
    int     width,
    int     height   
)   

目前我正在使用下面的代码,但它也返回不可读的字符(尽管与上面的代码不同)。

char* cr = tess.TesseractRect(
           subImage.data, 
           subImage.channels(), 
           subImage.channels() * subImage.size().width, 
           0, 
           0, 
           subImage.size().width, 
           subImage.size().height);   
tesseract::TessBaseAPI tess; 
cv::Mat sub = image(cv::Rect(50, 200, 300, 100));
tess.SetImage((uchar*)sub.data, sub.size().width, sub.size().height, sub.channels(), sub.step1());
tess.Recognize(0);
const char* out = tess.GetUTF8Text();

对于使用OpenCV/Tesseract的JavaCPP预设的任何人,这里是工作

Mat img = imread("file.jpg");
Mat gray = new Mat();
cvtColor(img, gray, CV_BGR2GRAY);
// api is a Tesseract client which is initialised
api.SetImage(gray.data().asBuffer(),gray.size().width(),gray.size().height(),gray.channels(),gray.size1())
cv::Mat image = cv::imread(argv[1]);
cv::Mat gray;
cv::cvtColor(image, gray, CV_BGR2GRAY);
PIX *pixS = pixCreate(gray.size().width, gray.size().height, 8);
for(int i=0; i<gray.rows; i++) 
    for(int j=0; j<gray.cols; j++) 
        pixSetPixel(pixS, j,i, (l_uint32) gray.at<uchar>(i,j));

首先,对subImage进行深度复制,以便将其存储在连续的内存块中:

cv::Mat subImage = image(cv::Rect(50, 200, 300, 100)).clone(); 

然后,用正确的参数初始化一个PIX头(我不知道怎么做)。

// ???? Put your own constructor here. 
PIX* pix = new PIX_HEADER(width, height, channels, depth); 

或者,手动创建:

PIX pix;
pix.width = subImage.width;
...

然后将像素数据指针设置为子图像数据指针

pix.data = subImage.data;

最后,确保在完成pix的工作之前,subImage对象没有超出作用域。