pytesseract image_to_string 不够准确

pytesseract image_to_string not accurate enough

我想使用 python 从裁剪后的数独图片中循环读取数字(这个语言中的新手......)并使用谷歌搜索推荐使用 pytesseract,

首先我尝试使用PIL阅读图片


from PIL import Image
import pytesseract

image = Image.open('./test.png')

width, height = image.size
left = 0
top = 0
i = 0
j = 0
while (top < height):
    while (left < width):
        crop_img = image.crop((left, top, left + width / 9,  top + height / 9))
        print(i, j, pytesseract.image_to_string(crop_img, config='--psm 6'))
        left += width / 9
        j += 1
    top += height / 9
    i += 1
    left = 0
    j = 0

print的结果是这样


0 0 5
0 1 3
0 2 a
0 3 po
0 4 7
0 5 |
0 6 So
0 7 7
0 8 _
1 0 6
1 1 
1 2 7
1 3 
1 4 9
1 5 
1 6 So
1 7 7
1 8 a
2 0 -
2 1 9
2 2 
2 3 P|
2 4 i
2 5 |
2 6 -
2 7 6
2 8 a
3 0 8
3 1 a
3 2 a
3 3 po
3 4 6
3 5 |
3 6 So
3 7 7
3 8 
4 0 4
4 1 -
4 2 -
4 3 
4 4 i
4 5 
4 6 -
4 7 _
4 8 
5 0 7
5 1 _
5 2 _
5 3 S|
5 4 
5 5 |
5 6 |
5 7 _
5 8 6.
6 0 |
6 1 6
6 2 7
6 3 P|
6 4 7
6 5 |
6 6 
6 7 
6 8 _
7 0 _
7 1 _
7 2 |
7 3 
7 4 
7 5 9
7 6 So
7 7 _
7 8 
8 0 |
8 1 |
8 2 
8 3 po
8 4 
8 5 |
8 6 So
8 7 
8 8 9

不够准确,但还算不错。

所以我的第二次尝试是使用 cv2 而不是 PIL,并且按照其他答案中的建议,我将图片移动为白色 bg 上的黑色文本(可能是它有点乱而不是最好的练习,欢迎提示:) )


import pytesseract
import cv2

image = cv2.imread('./test.png', 0)
height, width = image.shape
left = 0
top = 0
i = 0
j = 0
while (top < height):
    while (left < width):
        crop_img = image[int(top):int(top + height/9),
                         int(left):int(left + width/9)]
        thresh = cv2.threshold(
            crop_img, 155, 255, cv2.THRESH_BINARY_INV)[1]
        result = cv2.GaussianBlur(thresh, (5, 5), 0)
        result = 255 - result
        print(i, j, pytesseract.image_to_string(result, config='--psm 6'))
        left += width / 9
        j += 1
    top += height / 9
    i += 1
    left = 0
    j = 0

是什么给了我


  0 0 5
  0 1 3
  0 2 S|
  0 3 pS
  0 4 7
  0 5 |
  0 6 pS
  0 7 7
  0 8 7
  1 0 6
  1 1 po
  1 2 S|
  1 3 1
  1 4 9
  1 5 5 |
  1 6 pS
  1 7 7
  1 8 7
  2 0 pp
  2 1 Oo
  2 2 
  2 3 po
  2 4 
  2 5 |
  2 6 pS
  2 7 6
  2 8 |
  3 0 3
  3 1 po
  3 2 S|
  3 3 po
  3 4 6
  3 5 |
  3 6 pp
  3 7 7
  3 8 3)
  4 0 4
  4 1 |
  4 2 S|
  4 3 8
  4 4 |
  4 5 3]
  4 6 |
  4 7 7
  4 8 1
  5 0 7
  5 1 SS
  5 2 S|
  5 3 S|
  5 4 2
  5 5 |
  5 6 p
  5 7 |
  5 8 6.
  6 0 po
  6 1 6
  6 2 S|
  6 3 pS
  6 4 
  6 5 |
  6 6 
  6 7 
  6 8 7
  7 0 -
  7 1 -
  7 2 -
  7 3 4
  7 4 1
  7 5 9 |
  7 6 |
  7 7 i
  7 8 
  8 0 -
  8 1 -
  8 2 S|
  8 3 pS
  8 4 8
  8 5 |
  8 6 P|
  8 7 
  8 8 9)

在这两种情况下,我都保存了(.save(} 用于 PILimwrite 用于 cv2)用于调试的裁剪图像,实际上图片非常清晰,因为cv2 中的示例裁剪{ 2, 2 } 点(评估为空白点)裁剪的 img 是

完整的数独图像

提前致谢!

为此,我对图像使用了 OpenCV,然后将电路板保存到一个 numpy 数组中。我做的主要事情是为 image_to_string() 调用添加一个配置参数,以将输出限制为仅数字。不过这确实需要一段时间,因为它会像我认为你原来的那样单独预测每个数字。

import cv2
import numpy as np
import pytesseract

im = cv2.resize(cv2.imread('./test.png'), (900, 900))

out = np.zeros((9, 9), dtype=np.uint8)

for x in range(9):
    for y in range(9):
        num = pytesseract.image_to_string(im[10 + x*100:(x+1)*100 - 10, 10 + y*100:(y+1)*100 - 10, :], config='--psm 6 --oem 1 -c tessedit_char_whitelist=0123456789')
        if num:
            out[x, y] = num

这给了我你在你的 post 图像上的这个输出,其中 0 作为空格。

array([[5, 3, 0, 0, 7, 0, 0, 0, 0],
       [6, 0, 0, 1, 9, 5, 0, 0, 0],
       [0, 9, 8, 0, 0, 0, 0, 6, 0],
       [8, 0, 0, 0, 6, 0, 0, 0, 3],
       [4, 0, 0, 8, 0, 3, 0, 0, 1],
       [7, 0, 0, 0, 2, 0, 0, 0, 6],
       [0, 6, 0, 0, 0, 0, 2, 8, 0],
       [0, 0, 0, 4, 1, 9, 0, 0, 5],
       [0, 0, 0, 0, 8, 0, 0, 7, 9]], dtype=uint8)

它不是最干净的,但似乎工作得很好。