【问题标题】:How to write PIL image filter for plain pgm format?如何为纯 pgm 格式编写 PIL 图像过滤器?
【发布时间】:2011-05-15 07:36:18
【问题描述】:

如何为 pgm 纯 ascii 格式 (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 进行图形操作(谷歌: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()

【问题讨论】:

  • 谢谢。但是,为什么要返回 numpy.flipud(data)?我只需要返回数据。
  • 很久以前我这样做了...原因是图像不在笛卡尔坐标系中(反转y轴)。恕我直言,图像应该在没有翻转的笛卡尔系统中(或者有翻转,我不记得是哪种方式)。最后,使用 imread 和 imshow 时,上面正确显示了图像。
  • 啊……这很有道理。我早该想到的。再次感谢。

标签: python image image-processing python-imaging-library


【解决方案1】:

我目前处理这个问题的方式是通过numpy

  1. 将图像读入二维numpy 数组。您需要使用numpy,但我发现它比常规的 Python 2D 数组更易于使用
  2. 使用PIL.Image.fromarray将二维numpy数组转换为PIL.Image对象

如果您坚持使用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 2D 数组可以正常工作。

编辑

以下是我将如何处理包装器:

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 源代码(如果您有权访问)来确保发生这种情况。

【讨论】:

  • 那么问题来了:我如何写一个包装器?以及如何告诉 python 我有 PIL.image.open 的包装器?
猜你喜欢
  • 1970-01-01
  • 2017-08-31
  • 2014-04-25
  • 2012-09-27
  • 1970-01-01
  • 2017-12-07
  • 1970-01-01
  • 2012-12-17
相关资源
最近更新 更多