如何为pgm plain ascii format(P2)编写python映像库的过滤器。这里的问题是基本的PIL过滤器假设每个像素的字节数是恒定的。
我的目标是使用Image.open()打开feep.pgm。请参阅http://netpbm.sourceforge.net/doc/pgm.html或以下。
替代解决方案是我找到了PIL和所有主要图形程序支持的其他记录良好的ascii灰度格式。有什么建议吗?
feep.pgm:
P2
# feep.pgm
24 7
15
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 3 3 3 3 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 15 15 15 0
0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 15 0
0 3 3 3 0 0 0 7 7 7 0 0 0 11 11 11 0 0 0 15 15 15 15 0
0 3 0 0 0 0 0 7 0 0 0 0 0 11 0 0 0 0 0 15 0 0 0 0
0 3 0 0 0 0 0 7 7 7 7 0 0 11 11 11 11 0 0 15 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
编辑:感谢您的回答,它有效...... 但我需要一个使用Image.open()的解决方案。大多数python程序都使用PIL进行图形处理(google:python image open)。因此,我需要能够将过滤器注册到PIL。然后,我可以使用任何使用PIL的软件。我现在认为主要是scipy,pylab等依赖程序。
编辑好的,我想我现在知道了。下面是包装器pgm2pil.py:
import Image
import numpy
def pgm2pil(filename):
try:
inFile = open(filename)
header = None
size = None
maxGray = None
data = []
for line in inFile:
stripped = line.strip()
if stripped[0] == '#':
continue
elif header == None:
if stripped != 'P2': return None
header = stripped
elif size == None:
size = map(int, stripped.split())
elif maxGray == None:
maxGray = int(stripped)
else:
for item in stripped.split():
data.append(int(item.strip()))
data = numpy.reshape(data, (size[1],size[0]))/float(maxGray)*255
return numpy.flipud(data)
except:
pass
return None
def imageOpenWrapper(fname):
pgm = pgm2pil(fname)
if pgm is not None:
return Image.fromarray(pgm)
return origImageOpen(fname)
origImageOpen = Image.open
Image.open = imageOpenWrapper
misha的答案略有升级。必须保存Image.open以防止永不结束循环。如果pgm2pil返回None包装器调用pgm2pil,它返回None,调用pgm2pil ......
以下是测试功能(feep_false.pgm是格式错误的pgm,例如“P2” - >“FOO”,而lena.pgm只是 图像文件):
import pgm2pil
import pylab
try:
pylab.imread('feep_false.pgm')
except IOError:
pass
else:
raise ValueError("feep_false should fail")
pylab.subplot(2,1,1)
a = pylab.imread('feep.pgm')
pylab.imshow(a)
pylab.subplot(2,1,2)
b = pylab.imread('lena.png')
pylab.imshow(b)
pylab.show()
答案 0 :(得分:4)
我目前处理此问题的方式是numpy:
numpy
数组。您不需要使用numpy
,但我发现它比常规Python 2D数组更容易使用PIL.Image
PIL.Image.fromarray
对象
醇>
如果你坚持使用PIL.Image.open
,你可以编写一个试图首先加载PGM文件的包装器(通过查看标题)。如果是PGM,请使用上述步骤加载图像,否则只需将责任移交给PIL.Image.open
。
以下是我用来将 PBM 图像转换为numpy数组的一些代码。
import re
import numpy
def pbm2numpy(filename):
"""
Read a PBM into a numpy array. Only supports ASCII PBM for now.
"""
fin = None
debug = True
try:
fin = open(filename, 'r')
while True:
header = fin.readline().strip()
if header.startswith('#'):
continue
elif header == 'P1':
break
elif header == 'P4':
assert False, 'Raw PBM reading not implemented yet'
else:
#
# Unexpected header.
#
if debug:
print 'Bad mode:', header
return None
rows, cols = 0, 0
while True:
header = fin.readline().strip()
if header.startswith('#'):
continue
match = re.match('^(\d+) (\d+)$', header)
if match == None:
if debug:
print 'Bad size:', repr(header)
return None
cols, rows = match.groups()
break
rows = int(rows)
cols = int(cols)
assert (rows, cols) != (0, 0)
if debug:
print 'Rows: %d, cols: %d' % (rows, cols)
#
# Initialise a 2D numpy array
#
result = numpy.zeros((rows, cols), numpy.int8)
pxs = []
#
# Read to EOF.
#
while True:
line = fin.readline().strip()
if line == '':
break
for c in line:
if c == ' ':
continue
pxs.append(int(c))
if len(pxs) != rows*cols:
if debug:
print 'Insufficient image data:', len(pxs)
return None
for r in range(rows):
for c in range(cols):
#
# Index into the numpy array and set the pixel value.
#
result[r, c] = pxs[r*cols + c]
return result
finally:
if fin != None:
fin.close()
fin = None
return None
您必须稍微修改它以符合您的目的,即:
修改强>
以下是我将如何处理包装器:
def pgm2pil(fname):
#
# This method returns a PIL.Image. Use pbm2numpy function above as a
# guide. If it can't load the image, it returns None.
#
pass
def wrapper(fname):
pgm = pgm2pil(fname)
if pgm is not None:
return pgm
return PIL.Image.open(fname)
#
# This is the line that "adds" the wrapper
#
PIL.Image.open = wrapper
我没有写pgm2pil
,因为它与pgm2numpy
非常相似。唯一的区别是它将结果存储在PIL.Image
而不是numpy
数组中。我也没有测试包装器代码(抱歉,目前时间有点短)但这是一种相当常见的方法,所以我希望它可以工作。
现在,听起来您希望使用PIL进行图像加载的其他应用程序能够处理PGM。可以使用上述方法,但您需要确保在第一次调用PIL.Image.open
之前添加上面的上面的包装代码。您可以通过将包装器源代码添加到PIL源代码(如果您有权访问)来确保这一点。