我有点被这个问题困扰,我知道在堆栈溢出时有很多关于它的问题,但就我而言。什么都没有给出预期的结果。
上下文:
我正在与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周,现在找不到一种可行的解决方案,这是唯一可以提供准确结果的解决方案
最佳答案
您可以使用聚类算法根据颜色对像素进行聚类。字符较暗,并且MRZ区域中的对比度很好,因此,如果将其应用于 MRZ区域,则聚类方法很可能会给您带来良好的分割效果。
在这里,我通过从Internet上可以找到的样本图像获得的MRZ区域进行演示。
我使用彩色图像,应用一些平滑处理,转换为 Lab 色彩空间,然后使用kmeans(k = 2)将a,b通道数据聚类。该代码在python
中,但是您可以轻松地使其适应java
。由于kmeans算法的随机性,分段的字符将具有标签0或1。您可以通过检查cluster centers
轻松将其分类。与字符相对应的聚类中心在您使用的颜色空间中应具有dark
值。
我只是在这里使用了 Lab 颜色空间。您可以使用 RGB , HSV 甚至 GREY 来查看哪个更适合您。
像这样分割后,我认为您甚至可以使用字符的笔触宽度属性为自适应阈值的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
一些结果: