为啥不能用 PIL 和 pytesseract 获取字符串?
Posted
技术标签:
【中文标题】为啥不能用 PIL 和 pytesseract 获取字符串?【英文标题】:Why can't get string with PIL and pytesseract?为什么不能用 PIL 和 pytesseract 获取字符串? 【发布时间】:2019-12-02 16:06:33 【问题描述】:这是一个简单的Python 3光学字符识别(OCR)程序来获取字符串,我已经在这里上传了目标gif文件,请下载并保存为/tmp/target.gif
。
try:
from PIL import Image
except ImportError:
import Image
import pytesseract
print(pytesseract.image_to_string(Image.open('/tmp/target.gif')))
我把所有的错误信息都贴在这里,请修复它以从图像中获取字符。
/usr/lib/python3/dist-packages/PIL/Image.py:925: UserWarning: Couldn't allocate palette entry for transparency
"for transparency")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.5/dist-packages/pytesseract/pytesseract.py", line 309, in image_to_string
[output_type]()
File "/usr/local/lib/python3.5/dist-packages/pytesseract/pytesseract.py", line 308, in <lambda>
Output.STRING: lambda: run_and_get_output(*args),
File "/usr/local/lib/python3.5/dist-packages/pytesseract/pytesseract.py", line 208, in run_and_get_output
temp_name, input_filename = save_image(image)
File "/usr/local/lib/python3.5/dist-packages/pytesseract/pytesseract.py", line 136, in save_image
image.save(input_file_name, format=img_extension, **image.info)
File "/usr/lib/python3/dist-packages/PIL/Image.py", line 1728, in save
save_handler(self, fp, filename)
File "/usr/lib/python3/dist-packages/PIL/GifImagePlugin.py", line 407, in _save
_get_local_header(fp, im, (0, 0), flags)
File "/usr/lib/python3/dist-packages/PIL/GifImagePlugin.py", line 441, in _get_local_header
transparency = int(transparency)
TypeError: int() argument must be a string, a bytes-like object or a number, not 'tuple'
我用 bash 中的convert
命令转换它。
convert "/tmp/target.gif" "/tmp/target.jpg"
我在这里显示/tmp/target.gif
和/tmp/target.jpg
。
然后再次执行上面的python代码。
try:
from PIL import Image
except ImportError:
import Image
import pytesseract
print(pytesseract.image_to_string(Image.open('/tmp/target.jpg')))
pytesseract.image_to_string(Image.open('/tmp/target.jpg'))
什么都得不到,我得到空白字符。
对于 Trenton_M 的代码:
>>> img1 = remove_noise_and_smooth(r'/tmp/target.jpg')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in remove_noise_and_smooth
AttributeError: 'NoneType' object has no attribute 'astype'
Thalish Sajeed
对于 Thalish Sajeed 的代码:
省略print(pytesseract.image_to_string(Image.open(filename)))
引起的错误信息。
Type "help", "copyright", "credits" or "license" for more information.
>>> from PIL import Image
>>> import pytesseract
>>> import matplotlib.pyplot as plt
>>> import cv2
>>> import numpy as np
>>>
>>>
>>> def display_image(filename, length_box=60, width_box=30):
... if type(filename) == np.ndarray:
... image = filename
... else:
... image = cv2.imread(filename)
... plt.figure(figsize=(length_box, width_box))
... plt.imshow(image, cmap="gray")
...
>>>
>>> filename = r"/tmp/target.jpg"
>>> display_image(filename)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in display_image
File "/usr/local/lib/python3.5/dist-packages/matplotlib/pyplot.py", line 2699, in imshow
None else ), **kwargs)
File "/usr/local/lib/python3.5/dist-packages/matplotlib/__init__.py", line 1810, in inner
return func(ax, *args, **kwargs)
File "/usr/local/lib/python3.5/dist-packages/matplotlib/axes/_axes.py", line 5494, in imshow
im.set_data(X)
File "/usr/local/lib/python3.5/dist-packages/matplotlib/image.py", line 634, in set_data
raise TypeError("Image data cannot be converted to float")
TypeError: Image data cannot be converted to float
>>>
@Thalish Sajeed,为什么我的代码是 9244K
而不是 0244k
?
这是我测试过的示例文件。
提取的字符串。
@Trenton_M,更正您代码中的一些错字和丢失,并根据您的建议删除plt.show()
行。
>>> import cv2,pytesseract
>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>>
>>>
>>> def image_smoothening(img):
... ret1, th1 = cv2.threshold(img, 88, 255, cv2.THRESH_BINARY)
... ret2, th2 = cv2.threshold(th1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
... blur = cv2.GaussianBlur(th2, (5, 5), 0)
... ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
... return th3
...
>>>
>>> def remove_noise_and_smooth(file_name):
... img = cv2.imread(file_name, 0)
... filtered = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 41)
... kernel = np.ones((1, 1), np.uint8)
... opening = cv2.morphologyEx(filtered, cv2.MORPH_OPEN, kernel)
... closing = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel)
... img = image_smoothening(img)
... or_image = cv2.bitwise_or(img, closing)
... return or_image
...
>>>
>>> cv2_thresh_list = [cv2.THRESH_BINARY, cv2.THRESH_TRUNC, cv2.THRESH_TOZERO]
>>> fn = r'/tmp/target.jpg'
>>> img1 = remove_noise_and_smooth(fn)
>>> img2 = cv2.imread(fn, 0)
>>> for i, img in enumerate([img1, img2]):
... img_type = 0: 'Preprocessed Images\n',
... 1: '\nUnprocessed Images\n'
... print(img_type[i])
... for item in cv2_thresh_list:
... print('Thresh: '.format(str(item)))
... _, thresh = cv2.threshold(img, 127, 255, item)
... plt.imshow(thresh, 'gray')
... f_name = '0.jpg'.format(str(item))
... plt.savefig(f_name)
... print('OCR Result: \n'.format(pytesseract.image_to_string(f_name)))
... 预处理图像
在我的控制台中,所有输出信息如下:
Thresh: 0
<matplotlib.image.AxesImage object at 0x7fbc2519a6d8>
OCR Result: 10
15
20
Edfifi
10
2 o 30 40 so
so
Thresh: 2
<matplotlib.image.AxesImage object at 0x7fbc255e7eb8>
OCR Result: 10
15
20
Edfifi
10
2 o 30 40 so
so
Thresh: 3
<matplotlib.image.AxesImage object at 0x7fbc25452fd0>
OCR Result: 10
15
20
Edfifi
10
2 o 30 40 so
so
Unprocessed Images
Thresh: 0
<matplotlib.image.AxesImage object at 0x7fbc25464c88>
OCR Result: 10
15
20
Thresh: 2
<matplotlib.image.AxesImage object at 0x7fbc254520f0>
OCR Result: 10
15
2o
2o
30 40 50
Thresh: 3
<matplotlib.image.AxesImage object at 0x7fbc1e1968d0>
OCR Result: 10
15
20
字符串0244R
在哪里?
【问题讨论】:
【参考方案1】:让我们从 JPG 图像开始,因为 pytesseract 在 GIF 图像格式上运行时存在问题。 reference
filename = "/tmp/target.jpg"
image = cv2.imread(filename)
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, threshold = cv2.threshold(gray,55, 255, cv2.THRESH_BINARY)
print(pytesseract.image_to_string(threshold))
让我们尝试在此处分解问题。
您的图像噪声太大,无法通过 tesseract 引擎识别字母,我们使用一些简单的图像处理技术(例如灰度化和阈值处理)来去除图像中的一些噪声。
然后,当我们将其发送到 OCR 引擎时,我们看到这些字母被更准确地捕获。
如果你关注这个github link,你可以找到我测试过的笔记本
编辑 - 我用一些额外的图像清理技术更新了笔记本。 源图像太嘈杂,无法直接在图像上开箱即用。您需要使用图像清洁技术。
您可以改变阈值参数或将高斯模糊换成其他技术,直到获得所需的结果。
如果您希望在嘈杂的图像上运行 OCR - 请查看商业 OCR 提供商,例如 google-cloud-vision。他们每月免费提供 1000 个 OCR 电话。
【讨论】:
让我们continue this discussion in chat。【参考方案2】:首先:确保您已安装 Tesseract program(不仅仅是 python 包)
Jupyter Notebook of Solution:只有通过remove_noise_and_smooth
的图片才被OCR翻译成功。
尝试转换 image.gif 时,会生成 TypeError: int() argument must be a string, a bytes-like object or a number, not 'tuple'
。
重命名image.gif为image.jpg,生成TypeError
打开 image.gif 并“另存为”image.jpg,输出为空白,表示无法识别文本。
from PIL import Image
import pytesseract
# If you don't have tesseract executable in your PATH, include the following:
# your path may be different than mine
pytesseract.pytesseract.tesseract_cmd = "C:/Program Files (x86)/Tesseract-OCR/tesseract.exe"
imgo = Image.open('0244R_clean.jpg')
print(pytesseract.image_to_string(imgo))
无法从原始图像中识别出文本,因此可能需要在 OCR 之前进行后处理以进行清理
我创建了一个干净的图像,pytesseract 可以毫无问题地从中提取文本。该图片包含在下方,因此您可以使用自己的代码对其进行测试以验证其功能。
添加后处理
Improve Accuracy of OCR using Image Preprocessing
OpenCV
import cv2
import numpy as np
import matplotlib.pyplot as plt
def image_smoothening(img):
ret1, th1 = cv2.threshold(img, 88, 255, cv2.THRESH_BINARY)
ret2, th2 = cv2.threshold(th1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
blur = cv2.GaussianBlur(th2, (5, 5), 0)
ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
return th3
def remove_noise_and_smooth(file_name):
img = cv2.imread(file_name, 0)
filtered = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 9, 41)
kernel = np.ones((1, 1), np.uint8)
opening = cv2.morphologyEx(filtered, cv2.MORPH_OPEN, kernel)
closing = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel)
img = image_smoothening(img)
or_image = cv2.bitwise_or(img, closing)
return or_image
cv2_thresh_list = [cv2.THRESH_BINARY, cv2.THRESH_TRUNC, cv2.THRESH_TOZERO]
fn = r'/tmp/target.jpg'
img1 = remove_noise_and_smooth(fn)
img2 = cv2.imread(fn, 0)
for i, img in enumerate([img1, img2]):
img_type = 0: 'Preprocessed Images\n',
1: '\nUnprocessed Images\n'
print(img_type[i])
for item in cv2_thresh_list:
print('Thresh: '.format(str(item)))
_, thresh = cv2.threshold(img, 127, 255, item)
plt.imshow(thresh, 'gray')
f_name = '_.jpg'.format(i, str(item))
plt.savefig(f_name)
print('OCR Result: \n'.format(pytesseract.image_to_string(f_name)))
img1 将生成以下新图像:
img2 将生成这些新图像:
【讨论】:
以上是关于为啥不能用 PIL 和 pytesseract 获取字符串?的主要内容,如果未能解决你的问题,请参考以下文章
使用 PIL 从 url 打开图像文件以使用 pytesseract 进行文本识别
Python - PIL-pytesseract-tesseract验证码识别
python(pillow /tesseract-ocr/pytesseract)安装介绍