一、什么是.pgm图片?
.pgm文件由于模式的不同其数据存储方式也有所不同,下面介绍P2和P5模式的.pgm文件的格式。
1、P2模式的.pgm文件
P2模式的.pgm文件存储如下图所示:
其内容释义如下:
①第一行内容“P2”表示.pgm文件的模式。
②第二行“128, 120”表示图片的宽度、图片的高度。
③第三行“156”表示图片数据的最大值。
④第三行之后的文件表示图片的像素值,其是按行存放的。每个像素使用字符串来表示,比如灰度值可能的最大值为255,它的第一行第一列的像素值为100,那么该图像每个像素使用3个Ascii字符表示,第一行第一列数据为Ascii表示的”100”。*注意:P2格式文件数据部分当数据超过70个字节的时候,会自动换行。也就是说图像的每一行数据末尾,或者存储时超过70个字节时,需要进行换行。
2、P5模式的.pgm文件
P5模式的.pgm文件存储如下图所示(使用Notepad++打开的效果图):
其内容释义如下:
①第一行内容“P5”表示.pgm文件的模式。
②第二行“64, 60”表示图片的宽度、图片的高度。
③第三行“156”表示图片数据的最大值。
④第三行之后的文件表示图片的像素值。每个像素用可以用二进制表示。比如灰度值可能的最大值为255,它的第一行第一列像素值为100,那么该图像每个像素使用一个字节表示,第一行第一列为数值为100的二进制一个字节表示。如果灰度值可能的最大值是65535,那么它的第一行第一列为数值为100的二进制,使用两个字节表示(因为表示到65535需要两个字节)。对于P2模式的.pgm文件,每个像素数据之间没有间隔的连续存储,图像一行信息结束后从下一行第一列继续,两行图像数据之间也没有间隔的连续存储,直到将图像的所有信息表示完。
二、Python读取.pgm图片
1、读取P4~P6模式的.pgm图片
在读取以.pgm为扩展名的图片时,我们注意到模式有P2、P5等。这些模式的读取方式不同,对于P4~P6的模式,可以使用PIL非常方便的进行读取,如下代码。
from PIL import Image
def read_img():
im = Image.open("./data/faces.tar/faces/an2i/an2i_left_angry_open_4.pgm") # 读取文件
im.show() # 展示图片
print(im.size) # 输出图片大小
if __name__ == "__main__":
read_img() # 调用read_img()
即一句话便可以方便的读取.pgm图片,获取其像素点。
1、读取P2模式的.pgm图片
但是在使用上述方法读取P2模式的.pgm图片时,会报出如下错误:
错误信息提示使用PIL这种方式不可以读取此图片文件,经过一番资料的查找发现原因是:
Pillow only supports the binary versions of the PPM formats, P4-6, not the ascii versions: P1-3.
即PIL只支持二进制格式的P4-P6模式的读取,而不支持Ascii码格式的P1-P3模式的读取。
在pillow源码的模式定义为也对上述限定有所体现(源码地址:https://github.com/python-pillow/Pillow/blob/master/src/PIL/PpmImagePlugin.py#L27),如下图:
因此,P1-P3模式的图片无法使用PIL进行读取,读取方法如下:
import numpy as np
import matplotlib.pyplot as plt
def readpgm(name): # 读取图片
with open(name) as f:
lines = f.readlines()
# Ignores commented lines
for l in list(lines):
if l[0] == '#':
lines.remove(l)
# Makes sure it is ASCII format (P2)
assert lines[0].strip() == 'P2'
# Converts data to a list of integers
data = []
for line in lines[1:]:
data.extend([int(c) for c in line.split()]) # 读取数据
return (np.array(data[3:]),(data[1],data[0]),data[2])
data = readpgm('./data/faces.tar/faces/an2i/an2i_left_angry_open.pgm') # 返回值data[0]为数据,data[1]为shape,data[2]为出现的最大数据。
print(data)
plt.imshow(np.reshape(data[0],data[1])) #
plt.show()
参考资料:
https://github.com/python-pillow/Pillow/issues/860
https://www.cnblogs.com/liulijin/p/6840436.html
https://blog.csdn.net/colourful_sky/article/details/70244485