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

news2024/12/23 5:26:49

文章目录

  • 零. 前言
  • 一. pgm基本概念
  • 二. pgm基本信息读取
  • 三. 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。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1063298.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【有限域除法】二元多项式除法电路原理及C语言实现

二元多项式除法电路原理 例: g ( x ) = x 4 + x 2 + x + 1 g(x)=x^4 + x^2+x+1

C语言-字符串与输入输出

一、字符串 1、字符串简介 在 C 语言中,字符串实际上是使用空字符 \0 结尾的一维字符数组。因此,\0 是用于标记字符串的结束。 空字符(Null character)又称结束符,缩写 NUL,是一个数值为 0 的控制字符&…

深入了解“注意力”和“变形金刚” -第1部分

一、说明 这是一篇很长的文章,几乎讨论了人们需要了解的有关注意力机制的所有信息,包括自我注意、查询、键、值、多头注意力、屏蔽多头注意力和转换器,包括有关 BERT 和 GPT 的一些细节。因此,我将本文分为两部分。在本文中&#…

【JavaEE】JUC(Java.util.concurrent)常见类

文章目录 前言ReentrantLock原子类线程池信号量CountDownLatch相关面试题 前言 经过前面文章的学习我们大致了解了如何实现多线程编程和解决多线程编程中遇到的线程不安全问题,java.util.concurrent 是我们多线程编程的一个常用包,那么今天我将为大家分…

消息驱动 —— SpringCloud Stream

Stream 简介 Spring Cloud Stream 是用于构建消息驱动的微服务应用程序的框架,提供了多种中间件的合理配置 Spring Cloud Stream 包含以下核心概念: Destination Binders:目标绑定器,目标指的是 Kafka 或者 RabbitMQ&#xff0…

一款支持功能安全车规级 线性PMIC稳压器 NCV4274CDS50R4G 解决方案:高效率、更智能、强功能安全

关于车规级芯片: 关于车规级芯片(Automotive Grade Chip),车规级芯片是专门用于汽车行业的芯片,具有高可靠性、高稳定性和低功耗等特点,以满足汽车电子系统的严格要求。这些芯片通常用于车载电子控制单元&…

c++使用ifstream和ofstream报错:不允许使用不完整的类型

学习《C Primer》关于IO库的部分&#xff0c;输入284页的的代码&#xff0c;出现了报错&#xff1a; 不允许使用不完整的类型 原来的代码&#xff1a; #include <iostream> #include <vector> using namespace std;int main(int argc, char **argv) {ifstream in…

如何搭建一个 websocket

环境: NodeJssocket.io 4.7.2 安装依赖 yarn add socket.io创建服务器 引入文件 特别注意: 涉及到 colors 的代码&#xff0c;请采取 console.log() 打印 // 基础老三样 import http from "http"; import fs from "fs"; import { Server } from &quo…

分享几个优秀开源免费管理后台模版,建议收藏!

大家好&#xff0c;我是 jonssonyan 今天和大家分享一些免费开源的后台管理页面&#xff0c;帮助大家快速搭建前端页面。为什么要用模板&#xff1f;道理很简单&#xff0c;原因是方便我们快速开发。我们不应该花太多的时间在页面调整上&#xff0c;而应该把精力放在核心逻辑和…

关于滑块验证码的问题

这里写自定义目录标题 一、超级鹰二、图片验证模拟登录1、页面分析1.1、模拟用户正常登录流程1.2、识别图片里面的文字 2、代码实现 三、滑块模拟登录1、页面分析2、代码实现&#xff08;通过对比像素获取缺口位置&#xff09; 四、openCV1、简介2、代码3、案例 五、selenium 反…

Vue中如何进行数据库操作与数据持久化

在Vue中进行数据库操作与数据持久化 Vue.js作为一个流行的JavaScript框架&#xff0c;通常用于构建前端应用程序&#xff0c;但它本身并不提供数据库操作或数据持久化的功能。数据库操作通常由后端服务器处理&#xff0c;而Vue负责呈现和交互。然而&#xff0c;您可以使用Vue与…

P1-Python编辑器的选择和安装

1、Python编辑器的选择、安装及配置&#xff08;PyCharm、Jupyter&#xff09; PyCharm的安装&#xff1a; https://www.jetbrains.com/pycharm/PyCharm的配置&#xff1a; 1、创建新的项目 2、导入本地已有的Pytorch anaconda环境 配置环境中问题&#xff1a; https://bl…

Kitchen Racks

厨房置物架 完美&#xff01;&#xff01;&#xff01;

【车载开发系列】S19/HEX/BIN文件解析

【车载开发系列】S19/HEX/BIN文件解析 【车载开发系列】S19/HEX/BIN文件解析 【车载开发系列】S19/HEX/BIN文件解析一. 文件烧录原理二. 为什么要文件解析三. BIN格式文件1&#xff09;bin格式优点2&#xff09;bin格式缺点 四. S-record概述五. S19&#xff0c;MOT&#xff0c…

ExoPlayer架构详解与源码分析(3)——Timeline

系列文章目录 ExoPlayer架构详解与源码分析&#xff08;1&#xff09;——前言 ExoPlayer架构详解与源码分析&#xff08;2&#xff09;——Player 文章目录 系列文章目录前言Timeline单文件或者点播流媒体文件播放列表或者点播流列表有限可播的直播流无限可播的直播流有多个P…

机器学习---RBM、KL散度、DBN

1. RBM 1.1 BM BM是由Hinton和Sejnowski提出的一种随机递归神经网络&#xff0c;可以看做是一种随机生成的 Hopfield网络&#xff0c;是能够通过学习数据的固有内在表示解决困难学习问题的最早的人工神经网络之 一&#xff0c;因样本分布遵循玻尔兹曼分布而命名为BM。BM由二…

平台项目列表页实现(二)

这里写目录标题 一、顶部盒子设计1. 顶部盒子包含项目列表和添加项目、退出登录2个按钮 二、项目列表盒子设计三、添加项目盒子设计四、退出登录功能实现五、路由导航守卫实现六、展示项目信息七、bug修复1、当项目名称太长或者项目负责人太长&#xff0c;需要一行展示&#xf…

一文详解动态链表和静态链表的区别

1、引言 本文主要是对动态链表和静态链表的区别进行原理上的讲解分析&#xff0c;先通过对顺序表和动态链表概念和特点的原理性介绍&#xff0c;进而引申出静态链表的作用&#xff0c;以及其概念。通过这些原理性的概述&#xff0c;最后总结归纳出动态链表和静态链表的区别。本…

vector的介绍以及使用方式

目录 前言 1.vector的介绍 2.构造函数 3.迭代器 4.vector空间增长问题 5.vector的增删改查 6.vector迭代器失效问题 总结 前言 即我们的string之后&#xff0c;今天小编给大家要介绍一个我们stl中另外一个常用的容器vector&#xff0c;和我们的string一样我们的vector…

Vue中如何进行分布式任务调度与定时任务管理

在Vue中进行分布式任务调度与定时任务管理 分布式任务调度和定时任务管理是许多应用程序中的关键功能之一。它们用于执行周期性的、异步的、重复的任务&#xff0c;例如数据备份、邮件发送、定时报告生成等。在Vue.js应用中&#xff0c;我们可以结合后端服务实现分布式任务调度…