То, как я сейчас с этим справляюсь, это через numpy :
- Считать изображение в массив 2D
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
Вам придется немного изменить его, чтобы он соответствовал вашим целям, а именно:
- Работа с P2 (ASCII, оттенки серого) вместо P1 (ASCII, двухуровневый).
- Используйте другой контейнер, если вы не используете numpy. Обычные двухмерные массивы Python будут работать нормально.
EDIT
Вот как я буду обращаться с оберткой:
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 (если у вас есть доступ).