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

文章目录

  • 零. 前言
  • 一. 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 pltfile_type = None  # 全局的文件类型变量def read_pgm(file_path):global file_typewith 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.mzph.cn/news/96080.shtml

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

相关文章

1、内核加载模块

一、静态加载 1、新功能源码与内核源码一起编译进uImage文件内 新功能源码与Linux内核源码在同一目录结构下在linux-3.14/drivers/char/目录下编写hello.c文件&#xff0c;内容如下 #include <linux/module.h> #include <linux/kernel.h>int __init myhello_ini…

英语四六级高频核心词(故事版)

第一组&#xff1a;" A Century of Community Effort to Improve Quality of Life and Climate" In the early years of the 20th century, a small community found itself facing a decade of challenges. The most pressing issue was the mental quality of life…

理解C++强制类型转换

理解C强制类型转换 文章目录 理解C强制类型转换理解C强制转换运算符1 static_cast1.1. static_cast用于内置数据类型之间的转换1.2 用于指针之间的转换 1.3 用于基类与派生类之间的转换2. const_cast2.1示例12.2 示例2——this指针 3.reinterpret_cast4.dynamic_cast C认为C风格…

多普勒频率相关内容介绍

图1 多普勒效应 1、径向速度 径向速度是作用于雷达或远离雷达的速度的一部分。 图2 不同的速度 2、喷气发动机调制 JEM是涡轮机的压缩机叶片的旋转的多普勒频率。 3、多普勒困境 最大无模糊范围需要尽可能低的PRF&#xff1b; 最大无模糊速度需要尽可能高的PRF&#xff1b…

国庆看坚如磐石

坚如磐石上映了&#xff0c;可以在爱奇艺观看。 而博主在使用蓝牙耳机连接电脑的过程中&#xff0c;发现没有蓝牙开启选项&#xff0c;并且在服务的设备管理器中也没有找到&#xff0c;很明显这是缺少驱动导致的&#xff0c;因此便去联想官方网站下载对应的驱动。 这里可以输入…

【LLM】主流大模型体验(文心一言 科大讯飞 字节豆包 百川 阿里通义千问 商汤商量)

note 智谱AI体验百度文心一言体验科大讯飞大模型体验字节豆包百川智能大模型阿里通义千问商汤商量简要分析&#xff1a;仅从测试“老婆饼为啥没有老婆”这个问题的结果来看&#xff0c;chatglm分点作答有条理&#xff08;但第三点略有逻辑问题&#xff09;&#xff1b;字节豆包…

数据结构与算法(四):哈希表

参考引用 Hello 算法 Github&#xff1a;hello-algo 1. 哈希表 1.1 哈希表概述 哈希表&#xff08;hash table&#xff09;&#xff0c;又称散列表&#xff0c;其通过建立键 key 与值 value 之间的映射&#xff0c;实现高效的元素查询 具体而言&#xff0c;向哈希表输入一个键…

STM32复习笔记(四):看门狗

目录 &#xff08;一&#xff09;简介 &#xff08;二&#xff09;IWDG IWDG的CUBEMX工程配置 IWDG相关函数&#xff08;非常少&#xff0c;所以直接贴上来&#xff09;&#xff1a; &#xff08;三&#xff09;WWDG &#xff08;一&#xff09;简介 看门狗分为独立看门…

几种开源协议的区别(Apache、MIT、BSD、MPL、GPL、LGPL)

作为一名软件开发人员&#xff0c;你一定也是经常接触到开源软件&#xff0c;但你真的就了解这些开源软件使用的开源许可协议吗&#xff1f; 你不会真的认为&#xff0c;开源就是完全免费吧&#xff1f;那么让我们通过本文来寻找答案。 一、开源许可协议简述 开源许可协议是指开…

karmada v1.7.0安装指导

前言 安装心得 经过多种方式操作&#xff0c;发现二进制方法安装太复杂&#xff0c;证书生成及其手工操作太多了&#xff0c;没有安装成功&#xff1b;helm方式的安装&#xff0c;v1.7.0的chart包执行安装会报错&#xff0c;手工修复了报错并修改了镜像地址&#xff0c;还是各…

家居家纺经营配送小程序商城的作用是什么

家居家纺产品是每个家庭都必备的&#xff0c;无论商场还是小摊贩&#xff0c;市场中经营商家数量都比较多&#xff0c;而随着互联网电商发展&#xff0c;在实际经营中&#xff0c;传统线下商家也面临多个难题&#xff1a; 首先就是获客问题&#xff0c;线下渠道推广宣传方式单…

冒泡排序和选择排序

目录 一、冒泡排序 1.冒泡排序的原理 2.实现冒泡排序 1.交换函数 2.单躺排序 3.冒泡排序实现 4.测试 5.升级冒泡排序 6.升级版代码 7.升级版测试 二、选择排序 1.选择排序的原理 2.实现选择排序 1.单躺排序 2.选择排序实现 3.测试 ​4.修改 5.测试 一、冒泡排序…

MacBook 录制电脑内部声音

MacBook 录制电脑内部声音 老妈喜欢跳广场舞&#xff0c;现在广场舞音频下载都收费了&#xff01;没办法&#xff0c;只能自己录歌了&#xff0c;外录有杂音大家也都知道&#xff0c;所以就只能采用内录的方式然后再用 Audition 调整一下音量大小。 一、&#xff08;前置条件&a…

HVDC-MMC互连(1000MW,±320KV)使用聚合MMC模型进行优化的SPS模拟

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 模型概述&#xff1a; 本示例展示了一个SimPowerSystems&#xff08;SPS&#xff09;模型&#xff0c;使用基于模块化多电平变换器&#xff08;MMC&#xff09;技术的电压源换流器&#xff08;VSC&#xff09…

【AI视野·今日Robot 机器人论文速览 第四十九期】Fri, 6 Oct 2023

AI视野今日CS.Robotics 机器人学论文速览 Fri, 6 Oct 2023 Totally 29 papers &#x1f449;上期速览✈更多精彩请移步主页 Interesting: &#x1f4da;ContactGen, 基于生成模型的抓取手势生成&#xff0c;类人五指手。(from 伊利诺伊大学 香槟) 数据集&#xff1a;GRAB da…

docker系列6:docker安装redis

传送门 docker系列1&#xff1a;docker安装 docker系列2&#xff1a;阿里云镜像加速器 docker系列3&#xff1a;docker镜像基本命令 docker系列4&#xff1a;docker容器基本命令 docker系列5&#xff1a;docker安装nginx Docker安装redis 通过前面4节&#xff0c;对docke…

【接口技术】输入输出接口

【输入输出接口概念】外设接口功能及其一般结构&#xff0c;I/O端口编址方式&#xff0c;输入/输出数据传送方式&#xff0c;端口译码技术 【输入/输出接口】 外部设备及其信号 外部设备 输入设备 输出设备 复合输入/输出设备 外部设备的信号 数据信号&#xff08;数字量…

电脑提示MSVCP100.dll丢失错误怎么解决?分享四个解决方法帮你搞定

在平时我们使用电脑中&#xff0c;经常会遇到各种问题&#xff0c;比如msvcp100.dll文件丢失&#xff0c;那这个msvcp100.dll文件丢失需要怎么修复解决呢&#xff1f;和msvcp100.dll为什么会丢失呢&#xff0c;下面我一点点为大家解答与介绍解决msvcp100.dll丢失问题的方法。 一…

Redisson—分布式服务

一、 分布式远程服务&#xff08;Remote Service&#xff09; 基于Redis的Java分布式远程服务&#xff0c;可以用来通过共享接口执行存在于另一个Redisson实例里的对象方法。换句话说就是通过Redis实现了Java的远程过程调用&#xff08;RPC&#xff09;。分布式远程服务基于可…

【JVM】运行时数据区(内存区域划分)详解

文章目录 前言一、JVM 运行时数据区1, 堆2, Java 虚拟机栈3, 本地方法栈4, 程序计数器5, 元数据区 / 方法区 二、内存异常问题1, 栈溢出2, 内存溢出3, 内存泄露 总结 前言 &#x1f4d5;各位读者好, 我是小陈, 这是我的个人主页 &#x1f4d7;小陈还在持续努力学习编程, 努力通…