用python读取bmp图片
专栏:ExASIC Nov. 10, 2024, 2:18 p.m. 42 阅读
用python读取bmp图片

上次介绍了如何用python生成bmp图片,今天我们继续bmp的话题:用python读取bmp图片。

读取bmp文件头

从上一篇文章,我们知道bmp文件头就是开始的54字节。这54字节中包含了分辨率、rgb数据的偏移量、rgb数据的大小、文件大小等信息。

bmp_head_format.png

我们先用二进制方式读取文件的前54字节,再用struct.unpack()来解析数据。如下:

f = open("save1.bmp", 'rb')
bmp_header_b = f.read(0x36)
print(bmp_header_b)
print('')

bmp_header_s = struct.unpack('<2sI2H4I2H6I', bmp_header_b)
print(bmp_header_s)
print('')

以上篇文章生成的500x500的图片作为测试,输出结果如下:

py-bmp2-01.png

struct.unpack的参数'<2sI2H4I2H6I'中的<表示低字节在前,s表示按字符解析,I按无符号整数(4bytes),H按无符号的短型(2bytes)。s、I、H前的数字表示重复次数,4I就表示4个32位的数。

详见官方文档:
https://docs.python.org/3/library/struct.html

struct.unpack的返回值是一个元组(只读型的列表)。在这个例子中,bmp_header_s[0]就是b'BM',bmp_header_s[6]和bmp_header_s[7]就是分辨率的宽和高。可见struct.unpack很适合用来做bytes型数据流的解析。

把元组转换成class对象

class bmp:
    "data structure"

    def __init__(self, tp):
        self.tag = tp[0]
        self.fileSize = tp[1]
        #reserved tp[2]
        #reserved tp[3]
        self.rgbOffset = tp[4]
        self.infoSize = tp[5]
        self.width = tp[6]
        self.height = tp[7]
        self.pane = tp[8]
        self.color = tp[9]
        self.compress = tp[10]
        self.rgbSize = tp[11]
        #reserved tp[12]
        #reserved tp[13]
        #reserved tp[14]
        #reserved tp[15]
        
    def print_bmp_header(self):
        print("tag      :{}".format(self.tag))
        print("fileSize :{}".format(self.fileSize))
        print("rgbOffset:{}".format(self.rgbOffset))
        print("infoSize :{}".format(self.infoSize))
        print("width    :{}".format(self.width))
        print("height   :{}".format(self.height))
        print("pane     :{}".format(self.pane))
        print("color    :{}".format(self.color))
        print("compress :{}".format(self.color))
        print("rgbSize  :{}".format(self.rgbSize))
        
if __name__ == '__main__':

    # ...

    image = bmp(bmp_header_s)
    image.print_bmp_header()
    print('')       
    
    # ...

我们把bmp图片文件头的基本信息定义到class bmp里,用__init__函数里进行转换。在后面的操作中可以用image.width、image.height等来调用,比较方便。

py-bmp2-02.png

读取rgb数据

# bytearray
bmp_rgb_data_b = f.read()

# bytearray -> list
list_b = array.array('B', bmp_rgb_data_b).tolist()

# reshape -> 3d list
rgb_data_3d_list = numpy.reshape(list_b, (image.height, image.width, 3)).tolist()

第一步,接前面读取54字节bmp文件头的操作,f.read()不带参数即可读取剩余的所有字节。返回值是bytearray的类型。二进制文件、网络协议等操作函数都是bytearray类型。

第二步,把bytearray转换成list,再用numpy.reshape转换成多维列表。这里,我们转换成了(height, width, 3)的三维数据。第一和第二维是高和宽,第三个维度就是一个像素的blue、green、red。

上面的代码打印第一个和最后一个像素,结果如下:

# first & last pixels
print(rgb_data_3d_list[0][0])
print(rgb_data_3d_list[image.height-1][image.width-1])

# [0, 255, 0]
# [0, 255, 0]

总结

这篇文章简要介绍了读取bmp图片的方法、bytearray与list的转换、list的维度转换等。经过解析后把rgb数据读取到了一个3维列表里,方便后续处理。

注意:

  • 需要import struct、numpy、array等package。

  • 在读取rgb数据时没有考虑一行字节数非4整倍数的情形。

  • python读取图片有更好用的库。本文仅用来学习,实际项目最好不要重复造轮子。

感谢阅读,更多文章点击这里:【专栏:ExASIC】
最新20篇 开设专栏