如何为纯 pgm 格式编写 PIL 图像过滤器? [英] How to write PIL image filter for plain pgm format?

查看:27
本文介绍了如何为纯 pgm 格式编写 PIL 图像过滤器?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何为 pgm 纯 ascii 格式 (P2) 编写 python 成像库的过滤器.这里的问题是基本的 PIL 过滤器假设每个像素的字节数恒定.

How can I write a filter for python imaging library for pgm plain ascii format (P2). Problem here is that basic PIL filter assumes constant number of bytes per pixel.

我的目标是用 Image.open() 打开fep.pgm.请参阅 http://netpbm.sourceforge.net/doc/pgm.html 或以下.

My goal is to open feep.pgm with Image.open(). See http://netpbm.sourceforge.net/doc/pgm.html or below.

替代解决方案是我找到了 PIL 和所有主要图形程序支持的其他有据可查的 ascii 灰度格式.有什么建议吗?

Alternative solution is that I find other well documented ascii grayscale format that is supported by PIL and all major graphics programs. Any suggestions?

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等依赖程序.

edit: Thanks for the answer, It works... but I need a solution that uses Image.open(). Most of python programs out there use PIL for graphics manipulation (google: python image open). Thus, I need to be able to register a filter to PIL. Then, I can use any software that uses PIL. I now think mostly scipy, pylab, etc. dependent programs.

编辑 好的,我想我现在明白了.下面是包装器 pgm2pil.py:

edit Ok, I think I got it now. Below is the wrapper 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

米莎的回答略有升级.必须保存 Image.open 以防止永无止境的循环.如果 pgm2pil 返回 None 包装器调用 pgm2pil 返回 None 调用 pgm2pil ...

There is a slight upgrade to misha's answer. Image.open has to be saved in order to prevent never ending loops. If pgm2pil returns None wrapper calls pgm2pil which returns None which calls pgm2pil...

下面是测试函数(feep_false.pgm 是格式错误的 pgm,例如P2"->FOO",lena.pgm 只是 图像文件):

Below is the test function (feep_false.pgm is a malformed pgm e.g. "P2" -> "FOO" and lena.pgm is just the image file):

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:

The way I currently deal with this is through numpy:

  1. 将图像读入二维 numpy 数组.你不需要使用numpy,但我发现它比普通的Python 2D数组更容易使用
  2. 使用 PIL.Image.fromarray
  3. 将 2D numpy 数组转换为 PIL.Image 对象
  1. Read image into a 2D numpy array. You don't need to use numpy, but I've found it easier to use than the regular Python 2D arrays
  2. Convert 2D numpy array into PIL.Image object using PIL.Image.fromarray

如果您坚持使用 PIL.Image.open,您可以编写一个包装器来尝试首先加载 PGM 文件(通过查看标题).如果是 PGM,请使用上述步骤加载图像,否则只需将责任交给 PIL.Image.open.

If you insist on using PIL.Image.open, you could write a wrapper that attempts to load a PGM file first (by looking at the header). If it's a PGM, load the image using the steps above, otherwise just hands off responsibility to PIL.Image.open.

这是我用来将 PBM 图像转换为 numpy 的一些代码数组.

Here's some code that I use to get a PBM image into a numpy array.

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

您必须稍微修改它以适合您的目的,即:

You will have to modify it slightly to fit your purposes, namely:

  • 处理 P2(ASCII,灰度)而不是 P1(ASCII,双级).
  • 如果您不使用 numpy,请使用不同的容器.普通的 Python 2D 数组也能正常工作.

编辑

这是我将如何处理包装器:

Here is how I would handle a wrapper:

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 数组中.我也没有测试包装器代码(抱歉,目前时间有点短)但这是一种相当常见的方法,所以我希望它能够工作.

I didn't write pgm2pil because it's going to be very similar to pgm2numpy. The only difference will be that it's storing the result in a PIL.Image as opposed to a numpy array. I also didn't test the wrapper code (sorry, a bit short on time at the moment) but it's a fairly common approach so I expect it to work.

现在,听起来您希望使用 PIL 进行图像加载的其他应用程序能够处理 PGM.可以使用上述方法,但您需要确保在第一次调用 PIL.Image.open 之前 添加了上述包装器代码.您可以通过将包装源代码添加到 PIL 源代码(如果您有访问权限)来确保发生这种情况.

Now, it sounds like you want other applications that use PIL for image loading to be able to handle PGMs. It's possible using the above approach, but you need to be sure that the above wrapper code gets added before the first call to PIL.Image.open. You can make sure that happens by adding the wrapper source code to the PIL source code (if you have access).

这篇关于如何为纯 pgm 格式编写 PIL 图像过滤器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆