【问题标题】:Improving threshold result for Tesseract提高 Tesseract 的阈值结果
【发布时间】:2019-03-30 05:46:57
【问题描述】:

我有点被这个问题困扰,而且我知道在堆栈溢出方面有很多关于它的问题,但就我而言。没有给出预期的结果。

背景:

我正在使用 Android OpenCV 和 Tesseract,因此我可以读取护照中的 MRZ 区域。当相机启动时,我将输入帧传递给 AsyncTask,帧被处理,MRZ 区域被成功提取,我将提取的 MRZ 区域传递给函数 prepareForOCR(inputImage),该函数将 MRZ 区域作为灰色 Mat 并输出我将传递给 Tesseract 的带有阈值图像的位图。

问题:

问题是在对图像进行阈值处理时,我使用 blockSize = 13 和 C = 15 的自适应阈值处理,但给出的结果并不总是相同,具体取决于图像的照明和帧所在的一般条件采取。

我尝试过的:

首先,我将图像大小调整为特定大小 (871,108),因此输入图像始终相同,并且不依赖于使用的手机。 调整大小后,我尝试使用不同的 BlockSize 和 C 值

//toOcr contains the extracted MRZ area
Bitmap toOCRBitmap = Bitmap.createBitmap(bitmap);
Mat inputFrame = new Mat();
Mat toOcr = new Mat();
Utils.bitmapToMat(toOCRBitmap, inputFrame);
Imgproc.cvtColor(inputFrame, inputFrame, Imgproc.COLOR_BGR2GRAY);
TesseractResult lastResult = null;
for (int B = 11; B < 70; B++) {
    for (int C = 11; C < 70; C++){
        if (IsPrime(B) && IsPrime(C)){
            Imgproc.adaptiveThreshold(inputFrame, toOcr, 255, Imgproc.ADAPTIVE_THRESH_GAUSSIAN_C, Imgproc.THRESH_BINARY, B ,C);
            Bitmap toOcrBitmap = OpenCVHelper.getBitmap(toOcr);
            TesseractResult result = TesseractInstance.extractFrame(toOcrBitmap, "ocrba");
            if (result.getMeanConfidence()> 70) {
                if (MrzParser.tryParse(result.getText())){
                    Log.d("Main2Activity", "Best result with " + B + " : " + C);
                    return result;
                }
            }
        }
    }
}

使用下面的代码,经过阈值处理的结果图像是一张黑白图像,其置信度大于 70,出于隐私原因,我无法真正发布整张图像,但这里有一个剪辑过的图像和一个虚拟密码。

使用 MrzParser.tryParse 函数添加了对字符位置及其在 MRZ 中的有效性的检查,能够更正一些出现的情况,例如包含 8 而不是 B 的名称,并获得良好的结果,但需要花费很多时间,这是正常的,因为我在循环中对近 255 个图像进行了阈值处理,并添加了 Tesseract 调用。

我已经尝试获取出现最多但结果不同的 C 和 B 值列表。

问题:

有没有办法定义一个 C 和 blocksize 值,这样它总是给出相同的结果,可能会添加更多的 OpenCV 调用,所以输入图像比如增加对比度等等,我在网上搜索了 2 周现在我可以'找不到可行的解决方案,这是唯一能给出准确结果的解决方案

【问题讨论】:

  • 你尝试过简单的持股吗?
  • 股份持有?是的,如果这就是您的意思,我经历了简单的阈值处理:D,但它永远不会给出相同的结果,除非所有用户拍摄的图像在照明、对比度和护照纹理方面都是相同的。如此简单的阈值并不是一个可行的解决方案。
  • 哈哈是的,我的意思是阈值对不起。发布一些您的图像示例会很有帮助。例如,您得到的确切结果是什么,但并不令人满意?

标签: android opencv ocr tesseract opencv4android


【解决方案1】:

您可以使用聚类算法根据颜色对像素进行聚类。字符较暗,在 MRZ 区域有很好的对比度,因此如果将聚类方法应用到 MRZ 区域,很可能会为您提供良好的分割。

在这里,我使用从互联网上可以找到的示例图像获得的机读区区域进行演示。

我使用彩色图像,应用一些平滑,转换为 Lab 颜色空间,然后使用 kmeans (k=2) 对 a、b 通道数据进行聚类。代码位于python,但您可以轻松地将其调整为java。由于 kmeans 算法的随机性,分段字符将具有标签 0 或 1。您可以通过检查 cluster centers 轻松对其进行排序。对应于字符的簇中心在您使用的颜色空间中应该有一个dark 值。 我只是在这里使用了 Lab 色彩空间。您可以使用 RGBHSV 甚至 GRAY,看看哪个更适合您。

像这样分割之后,我认为您甚至可以使用字符笔画宽度的属性找到自适应阈值的 B 和 C 的良好值(如果您认为自适应阈值提供更好的质量输出)。

import cv2
import numpy as np

im = cv2.imread('mrz1.png')
# convert to Lab
lab = cv2.cvtColor(cv2.GaussianBlur(im, (3, 3), 1), cv2.COLOR_BGR2Lab)

im32f = np.array(im[:, :, 1:3], dtype=np.float32)
k = 2 # 2 clusters
term_crit = (cv2.TERM_CRITERIA_EPS, 30, 0.1)
ret, labels, centers = cv2.kmeans(im32f.reshape([im.shape[0]*im.shape[1], -1]), 
                                  k, None, term_crit, 10, 0)
# segmented image
labels = labels.reshape([im.shape[0], im.shape[1]]) * 255

一些结果:

【讨论】:

  • 感谢您的宝贵时间,您的算法如何处理对比度不同的图像,因为图像是从手机摄像头拍摄的,有时机读区的左侧部分较暗,而右侧部分有很好的对比。我无法提供一个真实的例子,因为我现在不在我的电脑前。只需在图像上放置一些阴影并查看结果。
  • @Reda 如果聚类对这些图像不起作用,您可以尝试阴影检测和去除方法作为预处理。由于聚类使用 a 和 b(色度)通道,因此它有可能在这些区域中表现更好。您甚至可以尝试增加集群数量,例如增加到 3。
猜你喜欢
  • 2017-07-21
  • 2016-06-02
  • 2016-11-14
  • 2011-06-01
  • 2016-11-23
  • 2018-02-22
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多