Juh*_*uha 5 python image image-processing python-imaging-library
如何为 pgm 纯 ascii 格式(P2)编写 python 成像库的过滤器。这里的问题是基本的 PIL 过滤器假设每个像素的字节数恒定。
我的目标是用 Image.open() 打开fep.pgm。请参阅http://netpbm.sourceforge.net/doc/pgm.html或以下。
替代解决方案是我找到了 PIL 和所有主要图形程序支持的其他有据可查的 ascii 灰度格式。有什么建议?
费用.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
Run Code Online (Sandbox Code Playgroud)
编辑:感谢您的回答,它有效...但我需要一个使用 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
Run Code Online (Sandbox Code Playgroud)
米沙的回答略有升级。必须保存 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()
Run Code Online (Sandbox Code Playgroud)
我目前处理这个问题的方式是通过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
Run Code Online (Sandbox Code Playgroud)
您必须稍微修改它以适合您的目的,即:
编辑
这是我将如何处理包装器:
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
Run Code Online (Sandbox Code Playgroud)
我没有写,pgm2pil因为它与pgm2numpy. 唯一的区别是它将结果存储在 aPIL.Image而不是numpy数组中。我也没有测试包装器代码(抱歉,目前时间有点短)但这是一种相当常见的方法,所以我希望它能够工作。
现在,听起来您希望其他使用 PIL 进行图像加载的应用程序能够处理 PGM。可以使用上述方法,但您需要确保在第一次调用PIL.Image.open. 您可以通过将包装源代码添加到 PIL 源代码(如果您有权访问)来确保发生这种情况。