创建二进制PBM / PGM / PPM

时间:2012-09-11 17:29:39

标签: python pbmplus

我正在尝试了解如何创建二进制PBM / PGM / PPM文件。据我所知,每种格式有两种类型:普通格式和原始格式。例如,黑色PBM 5x5的结构如下所示:

P1
# This is a comment
5 5
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1

所以你看它很简单:白色是0,黑色是1.但是,PBM有原始版本,如下所示:

'P4\n# This is a comment\n5 5\n\xf8\xf8\xf8\xf8\xf8'

我该怎么办? PBM格式的描述说:

A raster of Height rows, in order from top to bottom. Each row is Width bits, packed 8 to a byte, with don't care bits to fill out the last byte in the row. Each bit represents a pixel: 1 is black, 0 is white. The order of the pixels is left to right. The order of their storage within each file byte is most significant bit to least significant bit. The order of the file bytes is from the beginning of the file toward the end of the file. A row of an image is horizontal. A column is vertical. The pixels in the image are square and contiguous.

我不明白我需要做什么;我怀疑我可能需要使用structarray.array,但我不确定。我需要你的帮助;你能举一个Python的例子来创建这样的文件吗?

>>> size = (5, 5)
>>> array = [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]
>>> create_pbm(size, array)
'P4\n5 5\n\xf8\xf8\xf8\xf8\xf8'

我需要一个好的速度,因为我需要处理更大的图像(例如2000x5000)。但问题是我需要使用纯Python,没有ctypes和库。请帮助我,并举例说明如何创建二进制PBM文件?

如果你能告诉我有关二进制PGM和PPM处理的信息,那将会更加惊人。

谢谢!

1 个答案:

答案 0 :(得分:6)

我确信这里有很大的改进空间(就效率而言),但这是否正常工作?

import struct
def create_pbm(size,lst):
    out = ['P4\n'+' '.join(map(str,size))+'\n'] #header
    for j in xrange(0,len(lst),size[1]):
        #single row of data
        row = lst[j:j+size[1]]
        #padded string which can be turned into a number with `int`
        s = ''.join(map(str,row))+'0000000'
        #Turn the string into a number and pack it (into unsigned int) using struct. 
        vals = [struct.pack('B',int(s[i*8:(i+1)*8],2)) for i in xrange(size[0]//8+1) ]
        out.append(''.join(vals))
    return ''.join(out)

a = [1]*25 #flat black image.
print repr(create_pbm((5,5),a))

修改

至于阅读,这似乎有效:

def read_pbm(fname):
    with open(fname) as f:
        data = [x for x in f if not x.startswith('#')] #remove comments
    p_whatever = data.pop(0)  #P4 ... don't know if that's important...
    dimensions = map(int,data.pop(0).split())
    arr = []
    col_number = 0
    for c in data.pop(0):
        integer = struct.unpack('B',c)[0]
        col_number += 8
        bits = map(int,bin(integer)[2:])
        arr.extend(bits[:min(8,dimensions[0]-col_number)])
        if(col_number > dimensions[0]):
            col_number = 0 

    return (dimensions, arr)

这些文件格式是否需要是正方形的?这似乎不太可能。我很可能在尺寸部分混合了行/列。随意检查; - )。