Python中读取bmp文件

20

有没有一种不必使用PIL就能在Python中读取bmp文件的方法?我使用的是版本3,而PIL与此版本不兼容。我尝试过使用graphics.py中的Image对象(Image(anchorPoint, filename)),但它似乎只适用于gif文件。


这个页面声称拥有Python 3兼容版本的PIL。 - Thomas K
9个回答

15

在Python中,它可以简单地被读取为:

import os
from scipy import misc
path = 'your_file_path'
image= misc.imread(os.path.join(path,'image.bmp'), flatten= 0)

## flatten=0 if image is required as it is 
## flatten=1 to flatten the color layers into a single gray-scale layer

8
注意,在 SciPy 1.0 版本中,imread(等函数)已被弃用,并将在1.2版中移除。SciPy 1.2 将使用 imageio.imread - uhoh

9
我知道这个问题已经比较老了,但当我自己解决这个问题时,我找到了它,并且我认为这可能会帮助将来的某些人。
实际上,将BMP文件作为二进制数据读取非常容易。当然,这取决于你需要支持的广泛性和角落情况数量。
以下是一个简单的解析器,仅适用于1920x1080 24位BMP(例如从MS Paint保存的BMP)。不过,扩展它应该很容易。它将像python列表一样输出像红色图像这样的像素值:(255, 0, 0, 255, 0, 0, …)
如果你需要更健壮的支持,有关如何正确读取头文件的信息,请参阅此问题的答案:如何在Python中读取bmp文件头?。使用那些信息,你应该能够扩展下面的简单解析器以获得任何需要的功能。
如果需要更多有关BMP文件格式的信息,还可以在维基百科上找到:https://en.wikipedia.org/wiki/BMP_file_format
def read_rows(path):
    image_file = open(path, "rb")
    # Blindly skip the BMP header.
    image_file.seek(54)

    # We need to read pixels in as rows to later swap the order
    # since BMP stores pixels starting at the bottom left.
    rows = []
    row = []
    pixel_index = 0

    while True:
        if pixel_index == 1920:
            pixel_index = 0
            rows.insert(0, row)
            if len(row) != 1920 * 3:
                raise Exception("Row length is not 1920*3 but " + str(len(row)) + " / 3.0 = " + str(len(row) / 3.0))
            row = []
        pixel_index += 1

        r_string = image_file.read(1)
        g_string = image_file.read(1)
        b_string = image_file.read(1)

        if len(r_string) == 0:
            # This is expected to happen when we've read everything.
            if len(rows) != 1080:
                print "Warning!!! Read to the end of the file at the correct sub-pixel (red) but we've not read 1080 rows!"
            break

        if len(g_string) == 0:
            print "Warning!!! Got 0 length string for green. Breaking."
            break

        if len(b_string) == 0:
            print "Warning!!! Got 0 length string for blue. Breaking."
            break

        r = ord(r_string)
        g = ord(g_string)
        b = ord(b_string)

        row.append(b)
        row.append(g)
        row.append(r)

    image_file.close()

    return rows

def repack_sub_pixels(rows):
    print "Repacking pixels..."
    sub_pixels = []
    for row in rows:
        for sub_pixel in row:
            sub_pixels.append(sub_pixel)

    diff = len(sub_pixels) - 1920 * 1080 * 3
    print "Packed", len(sub_pixels), "sub-pixels."
    if diff != 0:
        print "Error! Number of sub-pixels packed does not match 1920*1080: (" + str(len(sub_pixels)) + " - 1920 * 1080 * 3 = " + str(diff) +")."

    return sub_pixels

rows = read_rows("my image.bmp")

# This list is raw sub-pixel values. A red image is for example (255, 0, 0, 255, 0, 0, ...).
sub_pixels = repack_sub_pixels(rows)

7
使用Pillow。安装完成后,只需导入即可。
from PIL import Image

然后您可以加载BMP文件

img = Image.open('path_to_file\file.bmp')

如果您需要将图像转换为 numpy 数组,请使用 np.array
img = np.array(Image.open('path_to_file\file.bmp'))

numpy数组只会是一维的。如果您的图像是RGB,则使用reshape()将其调整为正确的形状。例如:
np.array(Image.open('path_to_file\file.bmp')).reshape(512,512,3)

4
使用优秀的matplotlib库。
import matplotlib.pyplot as plt
im = plt.imread('image.bmp')

2

我曾经需要使用Python读取BMP文件的项目,这个过程非常有趣。实际上,最好的方法是先了解BMP文件格式(https://en.wikipedia.org/wiki/BMP_file_format),然后将其作为二进制文件读取以提取数据。

你需要使用Python的struct库进行数据提取。

你可以使用这个教程了解具体操作:https://youtu.be/0Kwqdkhgbfw


1

Ctypes是可行的,我已经使用过并坚持使用它,但它往往会产生相对脆弱的解决方案 - 比C本身更脆弱。这是因为ctypes的类型检查可能更好。对于非常稳定的API,ctypes可能非常好(特别是如果您想针对不仅是cpython而且还有pypy),但是如果您愿意坚持使用cpython,那么cython实际上可能更好。 - user1277476

1

1
常用的将PIL移植到Python 3.x的端口称为“Pillow”。 此外,我建议使用pygame库进行简单任务。它是一个功能丰富的库,可用于创建游戏 - 其中包括从一些常见图像格式中读取。也适用于Python 3.x。

0
前段时间,我需要从一款旧的科学软件中读取BMP文件,这个软件在一些程序中可以工作,但是Python的PIL却无法打开它。
BMP是一种相当简单的格式,可以很容易地通过numpy解析;你可能希望适应以下几行代码。
def load_Philips30XL_BMP(fname):
    """ 
    Experimental loading of BMPs from Philips30XL microscopes (they have an atypical format which cannot be loaded by imageio)
    See https://ide.kaitai.io/ for more information on BMP header. 
    """
    with open(fname, mode='rb') as file: # first analyze the header
        fileContent = file.read()
        ofs, w, h, bpp, compr = [int.from_bytes(fileContent[s:e], byteorder='little', signed=False) for s,e in 
                ((0x0a,0x0e),(0x12,0x16),(0x16,0x1a),(0x1c,0x1e),(0x1e,0x22))]
    assert bpp == 8, f'monochrome/LUT image assumed (8 bit per pixel); {fname} has {bpp}bpp'
    assert compr == 0, 'no decompression algorithm implemented'
    return np.fromfile(fname, dtype=np.uint8)[ofs:ofs+w*h].reshape(h,w)[::-1,:] # BMP is "upside down" - flip vertically

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接