• (十)图像数据的序列与反序列化



    欢迎访问个人网络日志🌹🌹知行空间🌹🌹


    1.Python中输入输出流

    Python的io模块提供了Python中处理各种类型输入输出的主要功能,Python中处理的主要有3种类型的io,分别是
    text I/O,binary I/Oraw I/O。这三种类型的具体对象都是文件对象,有时也被称为类文件对象。各种流对象处理不同的文件类型。例如,往binary流对像中写入str类型的对象会报类型错误TypeError,同样往text流对象中写入binary类型的内容时也会报错。

    text流对象主要处理str类型文件的读取和写入,当文件是以字节为单位存储时,通过text流对象可以使得文件的编解码和如换行符等的跨平台支持变的无感。最简单的创建text流对象的方式是通过open函数,如

    import io
    f = open('text.txt', 'r', encoding='utf8')
    # 在内存中的字节流可以通过io.StringIO来创建
    f = io.StringIO("some text")
    
    • 1
    • 2
    • 3
    • 4

    binary I/O用来处理类字节对象,并返回一个字节对象bytes object,Python中的bytes类和str差不多,只是在定义时引号前面加b,如bytes_data = b'data',bytes对象只支持ASCII码字符,任何二进制码超过127的字符在bytes对象中必须以转移序列来表示。类字节对象bytes-like object是支持缓存协议Buffer Protocol且能输出一个C语言连续缓存的对象,binary I/O不会自动对文件进行编解码和换行符转换。binary I/O用来处理非文本数据和或者想要手动控制文本数据的处理时。创建binary I/O对象的最简单方式是:

    f = open("myfile.jpg", "rb")
    # 从内存中读取
    f = io.BytesIO(b"some initial binary data: \x00\x01")
    
    • 1
    • 2
    • 3

    2.png文件格式简介

    png图片格式是可携式网络图形P ortable N etwork G raphics,PNG)是一种支援无损压缩的点阵图图形格式,支援索引、灰度、RGB三种颜色方案以及Alpha通道等特性。PNG的开发目标是改善并取代GIF作为适合网络传输的格式而不需专利许可,PNG于1997年3月作为知识性RFC 2083发布,于2004年作为ISO/IEC标准发布2

    png文件中,按字节读取后可以看到,开头的8个字节码总是十六进制数89 50 4E 47 0D 0A 1A 0A,这正是png格式文件的署名,是用来标识png格式的,所以只是修改了文件的后缀名,软件还是能够知道图片是png格式的。下面是通过pythonbuiltin.open函数按bytes对象读取png文件后得到的输出部分,

    p = "sample.png"
    with open(p,'rb') as f:
        img_data = f.read()
        print(img_data)
    # b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x0...'
    
    • 1
    • 2
    • 3
    • 4
    • 5

    可以看到前8个字节分别是\x89PNG\r\n\x1a\n,十六进制数0x50,0x4e,0x47,0x0d,oxoa分别对应的ASCII码正是P,N,G,CR,LF3

    png中定义了两种数据块,一种是PNG档案必须包含、读写软件也都必须要支援的关键块(critical chunk);另一种叫做辅助块(ancillary chunks),PNG允许软件忽略它不认识的附加块。

    关键数据块中有4个标准数据块:

    • 档案头数据块IHDR(header chunk):包含有图像基本信息,如宽高等,作为第一个数据块出现并只出现一次,其长度为固定的13个字节:

      描述

      长度

      图片宽度

      4字节

      图片高度

      4字节

      图像深度

      1字节

      颜色类型

      1字节

      压缩方法

      1字节

      过滤方式

      1字节

      扫描方式

      1字节

      如上面打开的图像的IHDR\x00\x00\x00\xb6\x00\x00\x00\x86可知图像宽高为\x00\x00\x00\xb6即182和\x00\x00\x00\x86即134。

    • 调色盘数据块PLTE(palette chunk):必须放在图像数据块之前。

    • 图像数据块IDAT(image data chunk):储存实际图像数据。PNG数据允许包含多个连续的图像数据块。

    • 图像结束数据IEND(image trailer chunk):放在档案尾部,表示PNG数据流结束。

    辅助数据块:常见的有:

    数据块识别符号数据块含意数据块位置限制
    cHRM基色和白色点数据块放在PLTE和IDAT之前
    gAMA图像γ数据块放在PLTE和IDAT之前
    pHYs物理像素尺寸数据块放在IDAT之前
    tIME图像最后修改时间数据块无限制
    tEXt档案基本讯息数据块无限制

    3.PIL库解析图像数据

    PIL库解析图像数据4

    • PIL.Image.open(fp, mode='r', formats=None)

    fp参数支持图像文件路径,如string/Path/文件对象。对于普通的png文件,可以通过PIL.Image.open(filename)函数来直接读取,

    from PIL import Image
    p = "sample.png"
    # 1.read from data path
    img = Image.open(p)
    # 获取图像的exif信息
    print(img.getexif())
    
    # 2.read from file object
    with open(p) as f:
         img_b = io.BytesIO(f.read())
         img = Image.open(img_b)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • PIL.Image.frombuffer(mode, size, data, decoder_name='raw', *args)

    基于字节缓存来创建一幅图像,值得注意的是frombuffer只解析像素数据,所以只能从像素数据(同pngIDAT部分)的字节缓存中恢复图像,不能直接使用png中读取的数据,因其包含有辅助数据等。可以解析Image.tobytesnumpy.tobytes(order='c'))生成的结果来构造图像。 同样还有Image.frombytes函数。

    import numpy as np
    
    with open(p) as f:
         img_b = io.BytesIO(f.read())
         img = Image.open(img_b)
    
    # 1.from Image.tobytes
    img_bytes = img.tobytes()
    img = Image.frombuffer('RGB', (182, 134), img_bytes)
    
    # 2.from numpy.tobytes
    fb = io.BytesIO()
    fb.write(img_bytes)
    img_bytes_buffer = fb.getbuffer()
    img_bytes = np.frombuffer(img_bytes_buffer,dtype=np.uint8).reshape(182, 134, -1)
    img_bytes = img_bytes.tobytes(order='C')img = Image.frombuffer('RGB', (182, 134), img_bytes)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4.opencv解析图像

    同样,使用OpenCV读取图像,可通过imread,也可以使用decode方法从内存数据中解析,譬如png格式的文件,可以先通过builtin.open读取成字节流,再使用np.frombuffer(bytes, dtype=uint8)构造图片的缓存数据后使用imdecode方法得到图像数据。

    from PIL import Image
    p = "sample.png"
    with open(p, 'rb') as f:
         img_bytes_data = f.read()
         img_buffer = np.frombuffer(img_bytes_data, dtype=np.uint8)
         img = cv2.imdecode(img_buffer, cv2.IMREAD_COLOR)
         cv2.cvtColor(img, cv2.COLOR_RGB2BGR, img)
         plt.imshow(img)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    当然这里只是一个示例,正常cv2.imdecode肯定不是通过这种方式使用,通常与cv2.imencode结合使用,用于图像数据的传递。

    5.labelme标注文件中的img_data数据解析

    import base64
    import cv2
    import numpy as np
    from PIL import Image
    from matplotlib import pyplot as plt
    
    json_path = "sample.json"
    data = json.load(open(json_path))
    data = data["imageData"]
    bytes_data = base64.b64decode(data)
    # 1.use Image to reconstruct image
    bd = io.BytesIO(bytes_data)
    img = Image.open(bd)
    
    # 2.use cv2.imdecode to reconstruct image
    img_data = np.frombuffer(bytes_data, dtype=np.uint8)
    img = cv2.imdecode(img_data, cv2.IMREAD_COLOR)
    cv2.cvtColor(img, cv2.COLOR_RGB2BGR, img)
    plt.imshow(img)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    图像数据保存到json文件中时,为了可视化的方便,通常对图像数据使用base64进行了编码,因此解析json中的img_data数据时要先使用base64解码得到图像数据的字节码,再使用numpy.frombuffer(bytes, dtype=uint8)方法创建cv2.imdecode能够解析的内存块数据,cv2.imdecode解析的是完整的图像数据而非只有像素数据,包括图像的宽高创建日期等信息,所以不需要额外的信息即可恢复图像。base64模块支持Base16/Base32/Base64/Base85编解码方法5,其作用主要是将二进制数据编码成可打印的ASCII码,以Base16算法为例,Base16编码会将字节切为4个一组,所以此编码后会用到2个字符,数据会变为原来的2倍。类推,Base32编码会将字节切为 5 个一组,每 5 个字节可以重组为8个字符。


    欢迎访问个人网络日志🌹🌹知行空间🌹🌹


    参考资料

  • 相关阅读:
    hdfswriter优化之提高写速度
    Junit执行源码分析,Junit是怎么跑起来的(二)
    MySql基础:utf8_unicode_ci、utf8_general_ci
    0X JavaSE-- 并发编程()
    1997-2019年樊纲市场化指数含stata do文档和原始数据
    前端音频处理之AudioMass调研
    代理服务器拒绝连接
    浅析 ArrayList
    【计算机组成&体系结构】电路基本原理与加法器设计
    【现代密码学原理】——密钥管理和其他公钥密码体制(学习笔记)
  • 原文地址:https://blog.csdn.net/lx_ros/article/details/126219126