美文网首页Python 3 Programming Specialization
第5课:二 、The (Py)Tesseract Library

第5课:二 、The (Py)Tesseract Library

作者: uptnv | 来源:发表于2020-06-12 15:53 被阅读0次

    [toc]

    Lecture: The (Py)Tesseract Library

    让我们首先使用 import PIL 库并展示 text图像

    from PIL import Image
    
    image = Image.open('readonly/text.png')
    display(image)
    
    image-20200604221358198

    让我们import pytesseract 库,并使用 dir() 函数看看这个库的一些函数

    import pytesseract
    dir(pytesseract)
    ---
    ['Output',
     'TesseractError',
     '__builtins__',
     '__cached__',
     '__doc__',
     '__file__',
     '__loader__',
     '__name__',
     '__package__',
     '__path__',
     '__spec__',
     'get_tesseract_version',
     'image_to_boxes',
     'image_to_data',
     'image_to_osd',
     'image_to_pdf_or_hocr',
     'image_to_string',
     'pytesseract']
    

    只有少量的函数,我觉得image_to_string 是合适的,我们使用 help() 查看一下

    help(pytesseract.image_to_string)
    ---
    Help on function image_to_string in module pytesseract.pytesseract:
    
    image_to_string(image, lang=None, config='', nice=0, output_type='string')
        Returns the result of a Tesseract OCR run on the provided image to string
    

    可见这个函数第一个输入参数是 an image, 剩下的是一些可选参数,返回的是OCR的结果。

    这是因为pytesseract库下面正在调用C++库,该库完成了所有艰苦的工作,而作者只是将所有调用传递给了底层tesseract可执行文件。 在使用python库时,这是一个常见问题,这意味着我们需要执行一些 Web 搜索,以便了解如何与tesseract进行交互。

    还有一个问题是没有说明输入参数 image 具体是什么,Is it a string to an image file? A PILLOW image?Something else? 我们通过查看源码了解到是一个 PILLOW image。因此输入一个 PIL image是可以作为这个函数的参数的。

    为这个函数撰写说明文档

    Hint: The doc line we needed was :param image: A PIL Image.Image file or an ndarray of bytes

    Ok, lets try and run tesseract on this image

    from PIL import Image
    
    image = Image.open('readonly/text.png')  # 代开文件为PILLOW image
    display(image)
    
    text = pytesseract.image_to_string(image)
    print(text)
    
    # 输出结果
    Behold, the magic of OCR! Using
    pytesseract, we’ll be able to read the
    contents of this image and convert it to
    text
    

    More Tesseract - 更复杂的情况

    前面我们使用的是清晰的 unambiguous 图片。现在我们试试混淆的图片

    from PIL import Image
    img = Image.open('readonly/Nosiy_OCR.PNG')
    display(img)
    
    image-20200604221323732

    现在我们尝试使用 tsseract -OCR 函数

    import pytesseract
    text = pytesseract.image_to_string(Image.open('readonly/Noisy_OCR.PNG'))
    print(text)
    
    # 输出结果
    e magic of OCR! Using pytesseract,
    le to read the contents of this
    
     
    
    d convert it to text
    

    识别的不是很好,我们现在采用一种方法:change the size of the image

    对文本图像的处理

    改变图片大小

    import PIL
    # 设置图片的 basewidth
    basewidth = 600
    
    img = Image.open('readonly/Noisy_OCR.PNG')
    # 对图片的比例 ratio 保持不变,我们使用basewidth除以实际的width
    wpercent = (basewidth / float(image.size[0]))
    # 则设置后的图片高度等于 实际高度乘以这个比例
    hsize = int(float(img.size[1]) * float(wpercent))
    # 最后,让我们调整图像大小。 抗锯齿 antialiasing是一种调整线条大小以使其平滑的特定方法
    img = img.resize((basewidth, hsize), PIL.Image.ANTIALIAS)
    
    # 另存为,展示
    img.save('resized_noise.png')
    display(img)
    
    # and run OCR
    text = pytesseract.image_to_string(Image.open('resized_nois.png')) 
    print(text)
    
    e magic of OCR! Using pytesseract,
    le to read the contents of this
    d convert it to text
    

    通过 resize 图片大小OCR的效果没有提升,下面我们把图像转为灰度图。

    greyscale - 灰度图

    我们看 PILLOW documention可以发现一种最简单的转换成灰度图的方法是使用 convert() 函数。

    img = Image.open('readonly/Noisy_OCR.png')
    img - img.convert('L')
    ---
    # Now lets save that image
    img.save('greyscale_noise.jpg')
    # And run OCR on the greyscale image
    text = pytesseract.image_to_string(Image.open('greyscale_noise.jpg')) 
    print(text)
    
    # 输出结果
    Behold, the magic of OCR! Using pytesseract,
    we'll be able to read the contents of this
    image and convert it to text
    

    运行效果非常好。

    binarization 二值图

    这意味着要分为两个不同的部分-在这种情况下为黑色和白色。 二值化通过称为阈值threshold的过程进行。 如果像素值大于阈值,它将被转换为黑色像素; 如果它低于阈值,它将被转换为白色像素。

    在 PILLOW 里调用函数:

    img = Image.open('readonly/Noisy_OCR.PNG').convert('1')
    img.save('black_white_noise.jpg')
    display(img)
    
    image-20200604222044753

    不过你也可以自己写二值化图像的函数:

    def binarize(image_to_transform, threshold):
        # 先转换成单通道的灰度图
      output_image=image_to_transform.convert("L")
     
      for x in range(output_image.width):
          for y in range(output_image.height):
              # 比较每一个像素
              if output_image.getpixel((x,y))< threshold: #注意这个函数的参数是一个元组(坐标)
                  output_image.putpixel( (x,y), 0 )
              else:
                  output_image.putpixel( (x,y), 255 )
      #now we just return the new image
        return output_image
    

    让我们在不同阈值范围内测试此功能。 请记住,您可以使用 range() 函数生成不同步长的数字列表。 使用开始,停止和步长调用 range()。 因此,让我们尝试 range(0,257,64),它应该生成5个不同阈值的图像

    for thresh in range(0,257,64):
        print("Trying with threshold " + str(thresh))
      # Lets display the binarized image inline
      display(binarize(Image.open('readonly/Noisy_OCR.PNG'), thresh))
      # And lets use tesseract on it. It's inefficient to binarize it twice but this is just for
      # a demo
      print(pytesseract.image_to_string(binarize(Image.open('readonly/Noisy_OCR.PNG'), thresh)))
    

    Tesseract and Photographs 对图像的OCR识别

    让我们尝试一下其它的图片OCR识别,例如一个门头:

    from PIL import Image
    import pytesseract
    
    image = Image.open('readonly/storefront.jpg')
    display(image)
    # ocr
    pytesseract.image_tostring(image) # 这个方法的对象是 PIL image
    
    image-20200604222759084
    ''
    

    OCR识别返回空的字符串,说明 Tesseract不能识别这幅图。我们在上一节学习过 裁剪图片的方法,crop the images;我们在这里尝试对原图进行裁剪。

    # First, lets set the bounding box. In this image the store name is in a box
    # bounded by (315, 170, 700, 270)
    bounding_box = (315, 170, 700, 270)
    # 对image进行裁剪
    title_image=image.crop(bounding_box)
    
    # 展示裁剪后的图片并对其进行OCR识别
    display(titlr_image)
    pytesseract.image_to_string(title_image)
    
    image-20200612145308979
    'FOSSIL'
    

    太好了,我们看到了如何通过减少一些问题来使该工作得以实现。 因此,现在我们已经能够拍摄图像,对其进行预处理(灰度图,二值化,裁剪),以至于希望看到文本,然后将其转换为python可以理解的字符串。

    观察图片可以发现墙上也有 商店的名字的标志。我们现在试试能不能识别它。

    # 首先我们 determine a bounding box来裁切这个小的标志
    bounding_box = (900, 420, 940, 445)
    little_sign = image.crop((990, 420, 940, 445))
    display(little_sign)
    
    image-20200604223005142

    这是一个很小的图片,我们首先对它 resize

    # 放大十倍
    new_size = (little_sign.width*10, little_sign.height*10)
    
    # Now lets check the docs for resize()
    help(little_sign.resize)
    ---
    Help on method resize in module PIL.Image:
    
    resize(size, resample=0, box=None) method of PIL.Image.Image instance
        Returns a resized copy of this image.
        
        :param size: The requested size in pixels, as a 2-tuple:
           (width, height).
        :param resample: An optional resampling filter.  This can be
           one of :py:attr:`PIL.Image.NEAREST`, :py:attr:`PIL.Image.BOX`,
           :py:attr:`PIL.Image.BILINEAR`, :py:attr:`PIL.Image.HAMMING`,
           :py:attr:`PIL.Image.BICUBIC` or :py:attr:`PIL.Image.LANCZOS`.
           If omitted, or if the image has mode "1" or "P", it is
           set :py:attr:`PIL.Image.NEAREST`.
           See: :ref:`concept-filters`.
        :param box: An optional 4-tuple of floats giving the region
           of the source image which should be scaled.
           The values should be within (0, 0, width, height) rectangle.
           If omitted or None, the entire source is used.
        :returns: An :py:class:`~PIL.Image.Image` object.
    
    # 我们可以看到在 resize 的时候可以选用不同的 filters 对图像进行处理,我们选用 Image.NEAREST 试试看
    display(little_sign.resize(new_size, Image.NEAREST))
    
    image

    上面是对图像进行resize操作时默认的 filter,让我们看看所有的filter 的效果

    options=[Image.NEAREST, Image.BOX, Image.BILINEAR, Image.HAMMING, Image.BICUBIC, Image.LANCZOS]
    for option in options:
        # lets print the option name
        print(option)
        # lets display what this option looks like on our little sign
        display(little_sign.resize(new_size, option))
    

    在这种情况下,Image.LANCZOS和Image.BICUBIC筛选器可以很好地完成工作。 让我们看看我们是否能够从调整后的图像中识别出文字

    new_size = (little_sign.width*10, little_sign.height*10)
    bigger_sign = little_sign.resize(new_size, Image.BICUBIC)
    # ocr输出
    pytesseract.image_to_string(bigger_sign)
    
    ''
    

    并没有识别,

    我们再对它尝试二值化 binarize,我么前面编写的二值化程序:

    def binarize(image_to_transform, threshold):
        output_image=image_to_transform.convert("L")
        for x in range(output_image.width):
            for y in range(output_image.height):
                if output_image.getpixel((x,y))< threshold:
                    output_image.putpixel( (x,y), 0 )
                else:
                    output_image.putpixel( (x,y), 255 )
        return output_image
    
    # Now, lets apply binarizations with, say, a threshold of 190, and try and display that
    # as well as do the OCR work
    binarized_bigger_sign = binarize(bigger_sign, 190)
    dispay(binarized_bigger_sign)
    pytesseract.image_to_string(binarized_bigger_sign)
    
    image-20200604223537291
    'Lae'
    

    好的,该文本几乎没有用。==我们应该如何选择最佳的二值化方法来使用?== 好的,让我们尝试一些非常简单的方法, 我们正在尝试检测一个英文单词“ FOSSIL”。 如果我们尝试从0到255的所有二值化,并查看列表中是否有英文单词,这可能是一种方法。 因此,让我们看看是否可以编写例程来执行此操作。

    # 首先加载英语字符的list 26个英语字母,存放在事先准备的地址
    eng_dict=[]
    with open ("readonly/words_alpha.txt", "r") as f:
        data=f.read()
        # now we want to split this into a list based on the new line characters
        eng_dict = data.split("\n")  # 将字符串分成一个列表
    
    # 现在,让其遍历所有可能的阈值并寻找英文单词,如果存在则将其打印出来
    for i in range(150,170):
        # 让我们将其二值化并将其转换为string值 命名为 strng
        strng = pytesseract.image_to_string(binarize(bigger_sign,i))
        # 我们要从文本中删除非字母字符,例如([%$]),这是首先执行的一种简短方法,让我们仅将字符串转换为小写
        strng=strng.lower()
        # then lets import the string package - it has a nice list of lower case letters
        import string
        # 现在让我们遍历字符串,逐个字符地查看它,并将其放入比较text中
        comparison=''
        for character in strng:
            if character in string.ascii_lowercase: # 是符串类型的话
                comparison = comparison + character
        # 最后,让我们在字典文件中搜索比较
        if comparison in eng_dict:
            # and print it if we find it
            print(comparison)
    
    fossil
    si
    fossil
    fossil
    gas
    gas
    sl
    sl
    sil
    

    好吧,这并不完美,但是我们看到 fossil 在字典中还有其他值。 这不是清除OCR数据的好方法。 在实践中使用语言或领域特定的词典可能很有用,尤其是在生成针对特定语言(例如医学知识库或位置)的搜索引擎时。

    至此,您已经了解了如何处理图像并将其转换为文本。 在本课程的下一个模块中,我们将更深入地研究计算机视觉库,该库可让我们检测其他事物。 然后,继续进行最终的项目!

    相关文章

      网友评论

        本文标题:第5课:二 、The (Py)Tesseract Library

        本文链接:https://www.haomeiwen.com/subject/kjxntktx.html