我有点被这个问题困扰,我知道在堆栈溢出时有很多关于它的问题,但就我而言。没有什么能得到预期的结果。
上下文:
我和Tesseract一起使用Android OpenCV,所以我可以阅读护照中的MRZ区域。启动相机后,将输入帧传递给AsyncTask,对该帧进行处理,成功提取MRZ区域,将提取的MRZ区域传递给函数prepareForOCR(inputImage),该函数将MRZ区域作为灰色Mat和Will输出我将传递给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和块大小值,以便始终提供相同的结果,也许添加更多的OpenCV调用,所以输入图像(例如增加对比度)等等,我在网上搜索了2周,现在我可以找不到可行的解决方案,这是唯一可以提供准确结果的解决方案
答案 0 :(得分:2)
您可以使用聚类算法根据颜色对像素进行聚类。字符较暗,并且MRZ区域中的对比度很好,因此,如果将聚类方法应用于 MRZ区域,则聚类方法很可能会给您带来很好的分割效果。
在这里我用从互联网上可以找到的样本图像获得的MRZ区域进行演示。
我使用彩色图像,应用一些平滑处理,转换为 Lab 色彩空间,然后使用kmeans(k = 2)对a,b通道数据进行聚类。该代码位于python
中,但是您可以轻松地使其适应java
。由于kmeans算法的随机性,分段的字符将带有标签0或1。您可以通过检查cluster centers
轻松地将其分类。与字符相对应的聚类中心在您使用的颜色空间中应具有一个dark
值。
我只是在这里使用了 Lab 色彩空间。您可以使用 RGB , HSV 或什至 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
一些结果: