Python中的实时OCR

时间:2018-10-19 20:01:29

标签: python image ocr image-recognition python-tesseract

问题

我正在尝试使用OpenCV捕获我的桌面,并让Tesseract OCR查找文本并将其设置为变量,例如,如果我要玩游戏并且捕获帧超过资源量,我希望它打印并使用它。一个完美的例子是minimumInterItemSpacing 只要他在游戏中失去健康,就会显示该健康并将其发送到启用蓝牙的气枪射击他。到目前为止,我有这个:

# imports
from PIL import ImageGrab
from PIL import Image
import numpy as np
import pytesseract
import argparse
import cv2
import os

fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter("output.avi", fourcc, 5.0, (1366, 768))

while(True):
        x = 760
        y = 968

        ox = 50
        oy = 22

        # screen capture
        img = ImageGrab.grab(bbox=(x, y, x + ox, y + oy))
        img_np = np.array(img)
        frame = cv2.cvtColor(img_np, cv2.COLOR_BGR2RGB)
        cv2.imshow("Screen", frame)
        out.write(frame)

        if cv2.waitKey(1) == 0:
                break

out.release()
cv2.destroyAllWindows()

它可以实时捕获并显示在窗口中,但是我不知道如何使它每帧识别文本并输出。

有什么帮助吗?

4 个答案:

答案 0 :(得分:3)

抓取屏幕并将其传递到tesseract进行OCR相当简单。

PIL(枕头)库可以在MacOS和Windows上轻松捕获帧。但是,此功能仅在Linux上才被添加,因此下面的代码可解决该问题(不存在)。 (我使用的是Ubuntu 19.10,但我的Pillow不支持它。)

基本上,用户使用屏幕区域矩形坐标启动程序。主循环不断抓住屏幕的该区域,并将其馈送到Tesseract。如果Tesseract在该图像中找到任何非空白文本,则将其写入 stdout

请注意,这不是正确的实时系统。不能保证及时性,每个帧所花费的时间都一样长。您的计算机可能会获得60 FPS或可能达到6 FPS。这也将极大地受到您要求监视的矩形的大小的影响。

#! /usr/bin/env python3

import sys
import pytesseract
from PIL import Image

# Import ImageGrab if possible, might fail on Linux
try:
    from PIL import ImageGrab
    use_grab = True
except Exception as ex:
    # Some older versions of pillow don't support ImageGrab on Linux
    # In which case we will use XLib 
    if ( sys.platform == 'linux' ):
        from Xlib import display, X   
        use_grab = False
    else:
        raise ex


def screenGrab( rect ):
    """ Given a rectangle, return a PIL Image of that part of the screen.
        Handles a Linux installation with and older Pillow by falling-back
        to using XLib """
    global use_grab
    x, y, width, height = rect

    if ( use_grab ):
        image = PIL.ImageGrab.grab( bbox=[ x, y, x+width, y+height ] )
    else:
        # ImageGrab can be missing under Linux
        dsp  = display.Display()
        root = dsp.screen().root
        raw_image = root.get_image( x, y, width, height, X.ZPixmap, 0xffffffff )
        image = Image.frombuffer( "RGB", ( width, height ), raw_image.data, "raw", "BGRX", 0, 1 )
        # DEBUG image.save( '/tmp/screen_grab.png', 'PNG' )
    return image


### Do some rudimentary command line argument handling
### So the user can speicify the area of the screen to watch
if ( __name__ == "__main__" ):
    EXE = sys.argv[0]
    del( sys.argv[0] )

    # EDIT: catch zero-args
    if ( len( sys.argv ) != 4 or sys.argv[0] in ( '--help', '-h', '-?', '/?' ) ):  # some minor help
        sys.stderr.write( EXE + ": monitors section of screen for text\n" )
        sys.stderr.write( EXE + ": Give x, y, width, height as arguments\n" )
        sys.exit( 1 )

    # TODO - add error checking
    x      = int( sys.argv[0] )
    y      = int( sys.argv[1] )
    width  = int( sys.argv[2] )
    height = int( sys.argv[3] )

    # Area of screen to monitor
    screen_rect = [ x, y, width, height ]  
    print( EXE + ": watching " + str( screen_rect ) )

    ### Loop forever, monitoring the user-specified rectangle of the screen
    while ( True ): 
        image = screenGrab( screen_rect )              # Grab the area of the screen
        text  = pytesseract.image_to_string( image )   # OCR the image

        # IF the OCR found anything, write it to stdout.
        text = text.strip()
        if ( len( text ) > 0 ):
            print( text )

这个答案与SO上的其他答案完全拼凑在一起。

如果您经常将此答案用于任何用途,则值得添加一个速率限制器以节省一些CPU。每个循环大概睡半秒钟。

答案 1 :(得分:1)

Tesseract是使用文件输入和输出的一次性命令行应用程序,这意味着每个OCR调用都会创建一个新进程并初始化一个新的Tesseract引擎,其中包括从磁盘读取数兆字节的数据文件。它是否适合用作实时OCR引擎将取决于确切的用例(更多的像素需要更多的时间),以及提供的parameters用于调整OCR引擎。最终可能需要进行一些实验,以将引擎调整为准确的场景,但也期望对帧进行OCR所需的时间可能会超过帧时间,并且可能需要减少OCR执行的频率,即以10-游戏可能以20 FPS而不是60 FPS以上的速度运行。

根据我的经验,在老化的CPU上使用4核(默认)的英语快速模型,在2200x1700px图像中相当复杂的文档可能需要0.5s到2s的任何时间,但是此“复杂文档​​”代表了最差的-案例方案,并且不对所识别文本的结构做任何假设。在许多情况下,例如从游戏屏幕中提取数据,可以进行一些假设以实现一些优化并加快OCR:

  • 缩小输入图像的尺寸。从屏幕上提取特定信息时,请尽可能将抓取的屏幕图像裁剪为仅该信息。如果您尝试提取健康值,请在健康值 just 周围裁剪图像。
  • 使用the "fast" trained models以提高准确性为代价来提高速度。您可以使用-l选项指定不同的模型,并使用--testdata-dir选项指定包含模型文件的目录。您可以下载多个模型,然后将文件重命名为“ eng_fast.traineddata”,“ eng_best.traineddata”等。
  • 使用--psm参数来防止您的方案不需要页面分割。 --psm 7可能是处理单条信息的最佳选择,但要尝试不同的值并找出最合适的信息。
  • 如果您知道将使用哪些字符(例如,您只是在寻找数字),请通过更改白名单配置值-c tessedit_char_whitelist='1234567890'来限制允许的字符集。

pytesseract是开始实施Tesseract的最佳方法,该库可以直接处理图像输入(尽管它在将图像传递给Tesseract之前将其保存到文件中),并使用{{ 1}}。

image_to_string(...)

答案 2 :(得分:0)

我知道他使用的程序是OCR的开放式OpenCV存储库,而屏幕上限则是Imagegrab。 OCR和Cappig的2个过程是在一段时间内完成的,真正的循环是非常快的。

Michael在这里也有该项目的git:https://github.com/michaelreeves08/footnot-health-detection,但它表明他忘了上传它...

我在这里是因为我正在寻找相同的东西,如果您在这方面取得了进展,请告诉我。我是从视频截图中阅读Michael的代码获得此信息的。

答案 3 :(得分:0)

好的,我遇到了与您相同的问题,因此我对此进行了一些研究,并且确定可以找到解决方案!首先,您将需要以下库:

  • cv2
  • pytesseract
  • 枕头(PIL)
  • numpy

安装:

  • 要安装cv2,只需在命令行/命令提示符中使用此命令: pip install opencv-python

  • 安装 pytesseract 有点困难,因为您还需要预安装 Tesseract ,它实际上是进行ocr读取的程序。首先,按照本教程上的说明安装Tesseract。然后,在命令行/命令提示符中使用以下命令: pip install pytesseract 如果您没有安装此权限,则使用ocr会收到错误消息

  • 要安装枕头,请在命令行/命令提示符中使用以下命令: python -m pip install --upgrade枕头 python3 -m pip install --upgrade枕头。使用python的人对我有用

  • 要安装NumPy,请在命令行/命令提示符中使用以下命令: pip install numpy 。以为它通常已经安装在大多数python库中。

代码: 这段代码是由我编写的,到目前为止,它可以按我想要的方式工作,并且类似于Michal的效果。它会显示在屏幕的左上方,并记录其图像,并显示当前使用OCR读取的图像的窗口显示。然后在控制台中,打印出在屏幕上读取的文本。

# OCR Screen Scanner
# By Dornu Inene
# Libraries that you show have all installed
import cv2
import numpy as np
import pytesseract

# We only need the ImageGrab class from PIL
from PIL import ImageGrab

# Run forever unless you press Esc
while True:
    # This instance will generate an image from
    # the point of (115, 143) and (569, 283) in format of (x, y)
    cap = ImageGrab.grab(bbox=(115, 143, 569, 283))

    # For us to use cv2.imshow we need to convert the image into a numpy array
    cap_arr = np.array(cap)

    # This isn't really needed for getting the text from a window but
    # It will show the image that it is reading it from

    # cv2.imshow() shows a window display and it is using the image that we got
    # use array as input to image
    cv2.imshow("", cap_arr)

    # Read the image that was grabbed from ImageGrab.grab using    pytesseract.image_to_string
    # This is the main thing that will collect the text information from that specific area of the window
    text = pytesseract.image_to_string(cap)

    # This just removes spaces from the beginning and ends of text
    # and makes the the it reads more clean
    text = text.strip()

    # If any text was translated from the image, print it
    if len(text) > 0:
        print(text)

    # This line will break the while loop when you press Esc
    if cv2.waitKey(1) == 27:
        break

# This will make sure all windows created from cv2 is destroyed
cv2.destroyAllWindows()

我希望这对您所需要的有所帮助,确实对我有帮助!