在 Python 中读取 bmp 文件

Posted

技术标签:

【中文标题】在 Python 中读取 bmp 文件【英文标题】:Reading bmp files in Python 【发布时间】:2012-05-03 20:48:39 【问题描述】:

有没有办法在不涉及使用 PIL 的 Python 中读取 bmp 文件? PIL 不适用于我拥有的版本 3。我尝试使用 graphics.py 中的 Image 对象 Image(anchorPoint, filename),但这似乎只适用于 gif 文件。

【问题讨论】:

This page 声称拥有 Python 3 兼容版本的 PIL。 【参考方案1】:

在 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

【讨论】:

注意,在 SciPy 1.0 imread (etc.) is depreciated and will be removed in 1.2; SciPy 1.2 将使用imageio.imread【参考方案2】:

我意识到这是一个老问题,但我在自己解决这个问题时发现了它,我认为这可能会在未来对其他人有所帮助。

实际上,将 BMP 文件作为二进制数据读取非常容易。当然,这取决于您需要支持的支持范围和极端情况。

下面是一个简单的解析器,仅适用于 1920x1080 24 位 BMP(如从 MS Paint 中保存的)。不过应该很容易扩展。它将像素值作为 python 列表吐出,例如 (255, 0, 0, 255, 0, 0, ...) 以红色图像为例。

如果您需要更强大的支持,请参阅有关如何正确阅读此问题的答案中的标题的信息:How to read bmp file header in python?。使用这些信息,您应该能够使用您需要的任何功能来扩展下面的简单解析器。

如果您需要,还有更多关于 BMP 文件格式的信息,请访问 wikipedia 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)

【讨论】:

【参考方案3】:

我必须在一个项目上工作,我需要使用 python 读取 BMP 文件,这很有趣,实际上最好的方法是查看 BMP 文件格式 (https://en.wikipedia.org/wiki/BMP_file_format) 然后将其作为二进制文件读取文件,以提取数据。

您需要使用 struct python 库来执行提取操作

您可以使用本教程来看看它是如何进行的https://youtu.be/0Kwqdkhgbfw

【讨论】:

【参考方案4】:

这取决于您要实现的目标以及在哪个平台上?

无论如何使用 C 库来加载 BMP 都可以工作,例如http://code.google.com/p/libbmp/ 或 http://freeimage.sourceforge.net/,C 库可以很容易地从 python 调用,例如使用 ctypes 或将其包装为 python 模块。

或者你可以编译这个版本的 PIL https://github.com/sloonz/pil-py3k

【讨论】:

Ctypes 是可行的,我已经使用并坚持使用它,但它往往会产生相对脆弱的解决方案 - 比 C 本身更严重。那是因为使用 ctypes 可以更好地进行类型检查。对于一个非常稳定的 API,ctypes 可能非常好(特别是如果您不仅想针对 cpython 还针对 pypy),但如果您愿意坚持使用 cpython,cython 实际上可能在许多事情上更好。【参考方案5】:

如果您在 Windows 中执行此操作,该站点应该允许您启动 PIL(和许多其他流行的包)并在大多数版本的 Python 中运行:Unofficial Windows Binaries for Python Extension Packages

【讨论】:

【参考方案6】:

PIL 到 Python 3.x 的通用端口称为“Pillow”。 另外,我建议使用 pygame 库来完成简单的任务。它是一个库,充满了创建游戏的功能——从一些常见的图像格式中读取就是其中之一。也适用于 Python 3.x。

【讨论】:

【参考方案7】:

为此使用枕头。安装好后直接导入

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)

【讨论】:

【参考方案8】:

使用优秀的matplotlib库

import matplotlib.pyplot as plt
im = plt.imread('image.bmp')

【讨论】:

以上是关于在 Python 中读取 bmp 文件的主要内容,如果未能解决你的问题,请参考以下文章

简单bmp图片处理工具——python实现

用标准c读取bmp文件的长宽?

关于怎么用C++读取bmp图片

用c#编写一个程序读取一张bmp图片的数据并转化为灰度图保存到文件中

用标准c读取某bmp文件的长宽及象素等信息需要哪些函数?

如何将多个 .img 图像转换为 .bmp 格式?