【问题标题】:How to save dpi info in py-opencv?如何在 py-opencv 中保存 dpi 信息?
【发布时间】:2019-08-19 09:12:34
【问题描述】:
import cv2

def clear(img):
    back = cv2.imread("back.png", cv2.IMREAD_GRAYSCALE)
    img = cv2.bitwise_xor(img, back)
    ret, img = cv2.threshold(img, 120, 255, cv2.THRESH_BINARY_INV)
    return img


def threshold(img):
    ret, img = cv2.threshold(img, 120, 255, cv2.THRESH_BINARY_INV)
    img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    ret, img = cv2.threshold(img, 248, 255, cv2.THRESH_BINARY)
    return img


def fomatImage(img):
    img = threshold(img)
    img = clear(img)
    return img


img = fomatImage(cv2.imread("1566135246468.png",cv2.IMREAD_COLOR))
cv2.imwrite("aa.png",img)

这是我的代码。但是当我尝试用 tesseract-ocr 识别它时,我收到了警告。

Warning: Invalid resolution 0 dpi. Using 70 instead.

我应该如何设置 dpi?

【问题讨论】:

    标签: opencv tesseract opencv3.0 python-tesseract


    【解决方案1】:

    AFAIK,OpenCV 不会设置它写入的 PNG 文件的 dpi,因此您正在寻找解决方法。这里有一些想法......


    方法 1 - 使用 PIL/Pillow 代替 OpenCV

    PIL/Pillow 可以将dpi 信息写入PNG 文件。所以你会:

    第 1 步 - 将您的 BGR OpenCV 图像转换为 RGB 以匹配 PIL 的通道顺序

    from PIL import Image
    RGBimage = cv2.cvtColor(BGRimage, cv2.COLOR_BGR2RGB)
    

    第 2 步 - 将 OpenCV Numpy 数组转换为 PIL 图像

    PILimage = Image.fromarray(RGBimage)
    

    第 3 步 - 使用 PIL 编写

    PILimage.save('result.png', dpi=(72,72))
    

    正如 Fred 在 cmets 中提到的,您同样可以以几乎相同的方式使用 Python Wand


    方法 2 - 使用 OpenCV 编写,然后使用一些工具进行修改

    您可以使用 Python 的 subprocess 模块来封装,例如,ImageMagick 并像这样设置 dpi:

    magick OpenCVImage.png -set units pixelspercentimeter -density 28.3 result.png
    

    您需要知道的是,PNG 使用公制(每厘米点数)而不是英制(每英寸点数),每英寸有 2.54 厘米,因此 72 dpi 变为每厘米 28.3 点。

    如果您的 ImageMagick 版本低于 v7,请将 magick 替换为 convert


    方法 3 - 使用 OpenCV 编写并自己插入 dpi

    您可以使用 OpenCV 的 imencode() 将文件写入内存。然后在文件中搜索IDAT(图像数据)块 - 这是包含图像像素的块,并在设置密度之前插入一个pHYs 块。然后写入磁盘。

    实际上并不难 - 它只有 9 个字节,请参阅 here 并查看答案末尾的 pngcheck 输出。

    此代码未经生产测试,但对我来说似乎工作得很好:

    #!/usr/bin/env python3
    
    import struct
    import numpy as np
    import cv2
    import zlib
    
    def writePNGwithdpi(im, filename, dpi=(72,72)):
       """Save the image as PNG with embedded dpi"""
    
       # Encode as PNG into memory
       retval, buffer = cv2.imencode(".png", im)
       s = buffer.tostring()
    
       # Find start of IDAT chunk
       IDAToffset = s.find(b'IDAT') - 4
    
       # Create our lovely new pHYs chunk - https://www.w3.org/TR/2003/REC-PNG-20031110/#11pHYs
       pHYs = b'pHYs' + struct.pack('!IIc',int(dpi[0]/0.0254),int(dpi[1]/0.0254),b"\x01" ) 
       pHYs = struct.pack('!I',9) + pHYs + struct.pack('!I',zlib.crc32(pHYs))
    
       # Open output filename and write...
       # ... stuff preceding IDAT as created by OpenCV
       # ... new pHYs as created by us above
       # ... IDAT onwards as created by OpenCV
       with open(filename, "wb") as out:
          out.write(buffer[0:IDAToffset])
          out.write(pHYs)
          out.write(buffer[IDAToffset:])
    
    ################################################################################
    # main
    ################################################################################
    
    # Load sample image
    im = cv2.imread('lena.png')
    
    # Save at specific dpi
    writePNGwithdpi(im, "result.png", (32,300))
    

    无论你使用哪种方法,你都可以使用pngcheck --v image.png来检查你做了什么:

    pngcheck -vv a.png
    

    样本输出

    File: a.png (306 bytes)
      chunk IHDR at offset 0x0000c, length 13
        100 x 100 image, 1-bit palette, non-interlaced
      chunk gAMA at offset 0x00025, length 4: 0.45455
      chunk cHRM at offset 0x00035, length 32
        White x = 0.3127 y = 0.329,  Red x = 0.64 y = 0.33
        Green x = 0.3 y = 0.6,  Blue x = 0.15 y = 0.06
      chunk PLTE at offset 0x00061, length 6: 2 palette entries
      chunk bKGD at offset 0x00073, length 1
        index = 1
      chunk pHYs at offset 0x00080, length 9: 255x255 pixels/unit (1:1). <-- THIS SETS THE DENSITY
      chunk tIME at offset 0x00095, length 7: 19 Aug 2019 10:15:00 UTC
      chunk IDAT at offset 0x000a8, length 20
        zlib: deflated, 2K window, maximum compression
        row filters (0 none, 1 sub, 2 up, 3 avg, 4 paeth):
          0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
          0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
          0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
          0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
          (100 out of 100)
      chunk tEXt at offset 0x000c8, length 37, keyword: date:create
      chunk tEXt at offset 0x000f9, length 37, keyword: date:modify
      chunk IEND at offset 0x0012a, length 0
    No errors detected in a.png (11 chunks, 76.5% compression).
    

    在编辑 PNG 块时,我还设法与作者一起设置了 tIME 块和 tEXt 块。他们是这样的:

    # Create a new tIME chunk - https://www.w3.org/TR/2003/REC-PNG-20031110/#11tIME
    year, month, day, hour, min, sec = 2020, 12, 25, 12, 0, 0    # Midday Christmas day 2020
    tIME = b'tIME' + struct.pack('!HBBBBB',year,month,day,hour,min,sec)
    tIME = struct.pack('!I',7) + tIME + struct.pack('!I',zlib.crc32(tIME))
    
    # Create a new tEXt chunk - https://www.w3.org/TR/2003/REC-PNG-20031110/#11tEXt
    Author = "Author\x00Sir Mark The Great"
    tEXt = b'tEXt' + bytes(Author.encode('ascii'))
    tEXt = struct.pack('!I',len(Author)) + tEXt + struct.pack('!I',zlib.crc32(tEXt))
    
    # Open output filename and write...
    # ... stuff preceding IDAT as created by OpenCV
    # ... new pHYs as created by us above
    # ... new tIME as created by us above
    # ... new tEXt as created by us above 
    # ... IDAT onwards as created by OpenCV
    with open(filename, "wb") as out:
       out.write(buffer[0:IDAToffset])
       out.write(pHYs)
       out.write(tIME)
       out.write(tEXt)
       out.write(buffer[IDAToffset:])
    

    关键字:OpenCV、PIL、Pillow、dpi、密度、imwrite、PNG、块、pHYs 块、Python、图像、图像处理、文本块、时间块、作者、评论

    【讨论】:

    • 也可以使用基于 ImageMagick 的 Python Wand。
    • 我添加了 Python Wand 作为 PIL 的替代品,感谢 Fred。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-16
    • 2020-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多