【Python】读取显示pgm图像文件

零. 前言

这学期要学多媒体信息隐藏对抗,发现其中的图像数据集文件都是pgm文件形式的。虽然是图像文件,但是却不能直接通过图像查看器来打开,上网一搜:”如何打开pgm文件?“多半是使用第三方软件photoshop之类的。

都是能写代码的人了,难道为了看几张图片还要下一个几G软件吗?

至此,我就开始考虑如何使用python读取pgm(Portable Gray Map)文件并显示出来。

一. pgm基本概念

如果使用记事本的方式打开,可以看到如下格式(以P2为例):

P2
width height
max_gray_value
pixel1 pixel2 pixel3 ... pixelN
...

例如下面的P5:

在这里插入图片描述

下面我们逐行解析一下:

  • 首行:Magic Number(魔数)是portable像素图片文件中的一个标识符,用于指示文件的类型和格式。以下是文件中可能出现的几种魔数及其含义:
    1. P1:表示这是一个ASCII格式的黑白二值图像。在这种格式下,像素的灰度值只能是0或1。
    2. P2:表示这是一个ASCII格式的灰度图像。在这种格式下,像素的灰度值可以是0到最大灰度值之间的任何整数。
    3. P3:表示这是一个ASCII格式的彩色图像。在这种格式下,每个像素包含三个分量(红、绿、蓝)的灰度值。
    4. P4:表示这是一个二进制格式的黑白二值图像。在这种格式下,像素的灰度值只能是0或1。
    5. P5:表示这是一个二进制格式的灰度图像。在这种格式下,像素的灰度值可以是0到最大灰度值之间的任何整数。
    6. P6:表示这是一个二进制格式的彩色图像。在这种格式下,每个像素包含三个分量(红、绿、蓝)的灰度值。

基于此,我们可以得到如下表格:

魔数类型编码方式文件后缀
P1单色图ASSIIPBM
P2灰度图ASSIIPGM
P3像素图ASSIIPPM
P4单色图二进制PBM
P5灰度图二进制PGM
P6像素图二进制PPM
  • 第二行:widthheight 表示图像的宽度和高度。

  • 第三行:

    • 如果是P1、P4:不存在颜色分量的最大值,即没有表示。
    • 如果是P2、P5:max_gray_value 表示灰度值的最大值(通常是255)。
    • 如果是P3、P6:max_color_value 表示颜色分量的最大值(通常是255)。
  • 后续:pixel1, pixel2, … pixelN 是图像的像素值。

    ​ 像素值可以是二进制或ASCII格式,如上图所示,如果无法解析成ASCII形式的字符,则表示这个pgm文件是二进制表示的pixels。

二. pgm基本信息读取

针对不同编码方式表示的像素,我们具有不同的读取与解析方案read_binary_pgm以及read_ascii_pgm。

代码如下:

def read_binary_pgm(file_path):
    with open(file_path, 'rb') as f:
        # 读取头部信息
        magic_number = f.readline().decode().strip()
        width, height = map(int, f.readline().decode().strip().split())
        max_gray_value = int(f.readline().decode().strip())

        # 读取像素值
        pixels = list(f.read())

        return (width, height, max_gray_value, pixels)


def read_ascii_pgm(file_path):
    with open(file_path, 'r') as f:
        # 读取头部信息
        header = f.readline().strip()
        width, height = map(int, f.readline().strip().split())
        max_gray_value = int(f.readline().strip())

        # 读取像素值
        pixels = [int(line) for line in f.readlines() if line.strip()]

        return (width, height, max_gray_value, pixels)


file_path = '../pgmfiles/1.pgm' # 注意修改你的读取路径

# width, height, max_gray_value, pixels = read_ascii_pgm(file_path)
width, height, max_gray_value, pixels = read_binary_pgm(file_path)

print(f"Width: {width}, Height: {height}")
print(f"Max Gray Value: {max_gray_value}")
print(f"Number of Pixels: {len(pixels)}")

这个小demo可以获取到这个pgm的基本信息:

三. pgm图像渲染

但是如何通过这些数据来渲染成图像呢?我们可以先将像素值转换为NumPy数组,并通过matplotlib将其显示为图像。

首先在上述代码顶部导包,并且在尾部追加图像显示代码即可:

import numpy as np
import matplotlib.pyplot as plt

# ...上述read代码...

# 将像素列表转换为NumPy数组
pixels_array = np.array(pixels).reshape(height, width)

# 显示图像
plt.imshow(pixels_array, cmap='gray', vmin=0, vmax=max_gray_value)
plt.show()

运行后,图像渲染如下:
在这里插入图片描述

四. 代码优化

最后,优化一下代码,根据首行的魔数来兼容P2和P5两种情况,实现函数read_pgm。

import numpy as np
import matplotlib.pyplot as plt

file_type = None  # 全局的文件类型变量

def read_pgm(file_path):
    global file_type

    with open(file_path, 'rb') as f:
        magic_number = f.readline().decode().strip()
        file_type = magic_number  # 更新全局的文件类型变量

        width, height = map(int, f.readline().decode().strip().split())
        max_gray_value = int(f.readline().decode().strip())

        if magic_number == 'P5':
            # 二进制格式
            pixels = list(f.read())
        elif magic_number == 'P2':
            # ASCII格式
            pixels = [int(line) for line in f.readlines() if line.strip()]
        else:
            raise ValueError("Unsupported file type.")

        return (width, height, max_gray_value, pixels)


def render_image(pixels, width, height, max_gray_value):
    # 将像素列表转换为NumPy数组
    pixels_array = np.array(pixels).reshape(height, width)

    # 显示图像
    plt.imshow(pixels_array, cmap='gray', vmin=0, vmax=max_gray_value)
    plt.show()


file_path = '../pgmfiles/1.pgm'

width, height, max_gray_value, pixels = read_pgm(file_path)

print(f"Width: {width}, Height: {height}")
print(f"Max Gray Value: {max_gray_value}")
print(f"Number of Pixels: {len(pixels)}")

# 显示图像
render_image(pixels, width, height, max_gray_value)

# 根据全局的文件类型变量进行其他操作
if file_type == 'P5':
    print("This is a binary format PGM file.")
elif file_type == 'P2':
    print("This is an ASCII format PGM file.")

基于此,其实也可以继续优化兼容其他4种文件,比如xx.ppm,xxx.pbm 文件。

再完善一点可以封装成一个小型的ppm/pgm/pbm图像显示器.exe。

不过那个就不在笔者的考虑范围内了。

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
读取pgm文件数据,可以使用以下方法之一: 方法一:使用Pillow库 1. 导入必要的库:from PIL import Image 2. 使用Image.open()函数打开pgm文件:im = Image.open(filepath) 3. 查看图片格式:print(im.mode) 4. 查看图片尺寸:print(im.size) 5. 可以使用im对象的其他方法来操作和处理pgm文件数据。例如,可以使用im.show()来显示图片。 方法二:使用numpy和matplotlib库 1. 导入必要的库:import numpy as np, matplotlib.pyplot as plt 2. 定义一个函数来读取pgm文件数据: def read_pgm(pgmf): assert pgmf.readline() == 'P5\n' (width, height) = [int(i) for i in pgmf.readline().split()] depth = int(pgmf.readline()) assert depth <= 255 raster = [] for y in range(height): row = [] for x in range(width): row.append(ord(pgmf.read(1))) raster.append(row) return raster 3. 调用read_pgm函数并传入pgm文件路径来读取数据:data = read_pgm(filepath) 4. 可以使用numpy和matplotlib绘图库来显示pgm文件数据。例如,使用plt.imshow(np.array(data))来显示数据。 请注意,根据不同的pgm文件格式,你可能需要根据具体情况调整代码。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [.pgm图片简介以及Python读取.pgm图片的方法](https://blog.csdn.net/quiet_girl/article/details/80904471)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [在python读取.pgm格式图像](https://blog.csdn.net/l_z_z_z/article/details/120800683)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

如果皮卡会coding

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值