如何在py-opencv中保存dpi信息?

时间:2019-08-19 09:12:34

标签: opencv tesseract opencv3.0 python-tesseract

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?

1 个答案:

答案 0 :(得分: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在评论中提到的那样,您可以同样地使用 Python魔杖


方法2-使用OpenCV编写,但随后使用某些工具进行修改

您可以使用Python的subprocess模块将其打包为 ImageMagick 并设置dpi,如下所示:

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

您需要知道的是,PNG使用公制(每厘米的点数)而不是英制(每英寸的点数),并且一英寸有2.54cm,因此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块时,我还设法通过Author设置了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,密度,写入,PNG,块,pHYs块,Python,图像,图像处理,tEXt块,tIME块,作者,注释