使用OpenCV和Python识别数字(简单的数字OCR)

6
我会尽力帮忙翻译。以下是您需要翻译的内容:

所以我正在尝试创建一个程序,可以看到一幅图像上的数字,并在控制台中打印整数。(我使用的是python 3)

例如,程序应该能够识别下面这张图像(实际程序要检查的图像)是数字2:

number 2

我曾尝试使用cv2.matchTemplate()将其与另一张包含数字2的图像进行比较,但每次蓝色像素的RGB值都会有些不同,并且图像可能会稍微变大或变小。例如下面的图像:

number 2

它还必须能够将其与所有其他蓝色数字图像(0-9)区分开来,例如以下图像:

number 5

我尝试过多个匹配模板代码,并创建了一个包含数字0-9图像的文件夹作为模板,但每次几乎每个数字都被识别成需要识别的数字。例如数字5在数字2的图像中得到了识别。如果它没有识别所有数字,则会识别错误的数字。
我尝试过以下方法: 但正如我之前所说,这些方法都存在问题。
我还尝试了查看每个图像中蓝色所占百分比的方法,但这些数字相差太小,无法通过观察其中的蓝色数量来区分数字。

有人有解决方案吗?我使用cv2.matchTemplate()是很愚蠢的吗?是否有更简单的选项?(我不介意使用库,因为这是代码的一部分,但我更喜欢编写它,而不是使用库)


我认为这个问题过于宽泛/模糊,可能不适合在Stack Overflow上提问。 - AMC
3个回答

4

不要使用模板匹配,更好的方法是使用Pytesseract OCR来使用image_to_string()读取数字。但在执行OCR之前,您需要对图像进行预处理。为了实现最佳的OCR性能,预处理后的图像应该是黑色文本/数字/字符,背景为白色。一个简单的预处理步骤是将图像转换为灰度图像,使用Otsu的阈值来获得二进制图像,然后反转图像。以下是预处理步骤的可视化:

输入图像->灰度图像->Otsu的阈值->反转图像准备进行OCR

enter image description here enter image description here enter image description here enter image description here

来自 Pytesseract OCR 的结果

2

这是使用其他图像得到的结果:

enter image description here enter image description here enter image description here enter image description here

2

enter image description here enter image description here enter image description here enter image description here

5

我们使用--psm 6配置选项来假定一个单一统一的文本块。更多配置选项请参见此处
代码
import cv2
import pytesseract

pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"

# Load image, grayscale, Otsu's threshold, then invert
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]
invert = 255 - thresh

# Perfrom OCR with Pytesseract
data = pytesseract.image_to_string(invert, lang='eng', config='--psm 6')
print(data)

cv2.imshow('thresh', thresh)
cv2.imshow('invert', invert)
cv2.waitKey()

注意:如果您坚持使用模板匹配,您需要使用比例变化的模板匹配。查看如何隔离轮廓内的所有内容、缩放并测试与图像的相似性?Python OpenCV线检测来检测图像中的X符号以获取一些示例。如果您确定您的图像是蓝色的,那么另一种方法是使用cv2.inRange()进行颜色阈值处理以获取二进制掩模图像,然后在图像上应用OCR。


你输入的图像在控制台上输出了“5”。你是否加载了正确的图像? - nathancy
我也在使用Windows 10,Python 3.7.4,但是我使用的numpy==1.18.1,opencv-python==4.1.2.30,pytesseract==0.3.1与你的不同。 - kaci
不,我没有。数字图片实际上是裁剪后的图像。原始图像更大,并且数字周围有黑色边框,因此我只是像平常一样裁剪了图像,但使用了一个10像素的边框。 - kaci
不,那些数字图像就是我所使用的图像。但它们来自于其他我裁剪成数字图像的图像。我只是让程序将它们裁剪成带有黑色边框的图像,并检查那些带边框的图像而不是没有边框的图像。 - kaci
它将9识别为您的程序中的o。您知道如何解决这个问题吗?我已经尝试了模糊图像和稍微更改--psm值,但这只会使它成为Qf}。 图片:https://imgur.com/a/ZT7tkYP - kaci
显示剩余11条评论

2
鉴于您提供了可爱的常规输入,我认为你需要做的就是与模板进行简单比较。由于您未提供代码和输出,很难确定可能出了什么问题。
非常简单...
1. 将您的输入重新调整为模板的大小。 2. 对每个模板,使用任何简单的匹配评估计算输入中的匹配情况。一个简单的匹配计数就足够了:两个图像之间有多少像素匹配。 3. 得分最高的模板是识别结果。
您可能还想设置一个更低的阈值来声明匹配,也许基于该模板与其他模板的匹配程度:任何识别都必须明显超过两个不同模板之间的匹配。

0

如果您没有访问OCR引擎的权限,那么您可以通过KNN分类器构建自己的OCR系统。在这个例子中,实现不应该很困难,因为您只需要对数字进行分类。OpenCV提供了一个非常简单的KNN实现。

分类器是使用从已知类别的样本中计算出的特征进行训练的。在这种情况下,您有10个类(如果您正在处理数字0-9),因此您可以准备一个带有数字的“模板”,提取一些特征,训练分类器并将其用于分类新实例。

所有这些都可以在OpenCV中完成,无需额外的库,而且KNN(对于这种应用)具有超过可接受的准确率。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接