使用PIL从字典创建图像

时间:2015-07-18 06:42:32

标签: python python-imaging-library

我有一个字典,它将坐标元组(在(0,0)到(199,199)范围内)映射到灰度值(0到255之间的整数)。是否有一种很好的方法来创建一个具有指定坐标处的指定值?我喜欢只使用PIL到使用scipy的解决方案。

3 个答案:

答案 0 :(得分:3)

您可以尝试image.putpixel()更改特定位置的像素颜色。示例代码 -

from PIL import Image
from random import randint

d = {(x,y):randint(0,255) for x in range(200) for y in range(200)}
im = Image.new('L',(200,200))

for i in d:
    im.putpixel(i,d[i])

im.save('blah.png')

它给了我一个像 -

的结果

enter image description here

答案 1 :(得分:3)

你可以用putpixel()来做,但这可能涉及成千上万的电话。这有多重要取决于字典中定义了多少个坐标元组。我已经将每个当前答案中显示的方法包括在内以进行比较(包括在添加任何基准测试之前我自己的方法,但是现在我对它如何初始化数据缓冲区进行了一些小改动,可以大大加快它的速度)。

为了进行公平竞争,出于测试目的,输入字典随机选择图像中的1/2可能像素来定义,并允许将其余像素设置为默认background颜色。 Anand S Kumar的答案目前不做后者,但下面显示的略有修改版本确实如此。

全部从数据中生成相同的图像。

from __future__ import print_function
import sys
from textwrap import dedent
import timeit

N = 100  # number of executions of each algorithm
R = 3  # number of repeations of executions

# common setup for all algorithms - is not included in algorithm timing
setup = dedent("""
    from random import randint, sample, seed
    from PIL import Image

    seed(42)
    background = 0  # default color of pixels not defined in dictionary
    width, height = 200, 200

    # create test dict of input data defining half of the pixel coords in image
    coords = sample([(x,y) for x in xrange(width) for y in xrange(height)],
                    width * height // 2)
    d = {coord: randint(0, 255) for coord in coords}
""")

algorithms = {
    "Anand S Kumar": dedent("""
        im = Image.new('L', (width, height), color=background)  # set bgrd
        for i in d:
            im.putpixel(i, d[i])
    """),

    "martineau": dedent("""
        data = bytearray([background] * width * height)
        for (x, y), v in d.iteritems():
            data[x + y*width] = v
        im = Image.frombytes('L', (width, height), str(data))
    """),

    "PM 2Ring": dedent("""
        data = [background] * width * height
        for i in d:
            x, y = i
            data[x + y * width] = d[i]
        im = Image.new('L', (width, height))
        im.putdata(data)
    """),
}

# execute and time algorithms, collecting results
timings = [
    (label,
     min(timeit.repeat(algorithms[label], setup=setup, repeat=R, number=N)),
    ) for label in algorithms
]

print('fastest to slowest execution speeds (Python {}.{}.{})\n'.format(
        *sys.version_info[:3]),
        '  ({:,d} executions, best of {:d} repetitions)\n'.format(N, R))
longest = max(len(timing[0]) for timing in timings)  # length of longest label
ranked = sorted(timings, key=lambda t: t[1])  # ascending sort by execution time
fastest = ranked[0][1]
for timing in ranked:
    print("{:>{width}} : {:9.6f} secs, rel speed {:4.2f}x, {:6.2f}% slower".
            format(timing[0], timing[1], round(timing[1]/fastest, 2),
                   round((timing[1]/fastest - 1) * 100, 2), width=longest))

输出:

fastest to slowest execution speeds (Python 2.7.10)
   (100 executions, best of 3 repetitions)

    martineau :  0.255203 secs, rel speed 1.00x,   0.00% slower
     PM 2Ring :  0.307024 secs, rel speed 1.20x,  20.31% slower
Anand S Kumar :  1.835997 secs, rel speed 7.19x, 619.43% slower

答案 2 :(得分:2)

正如马蒂诺所说,当你修改一些随机像素时,putpixel()是可以的,但它对于构建整个图像并不是那么有效。我的方法类似于他,除了我使用一个整数列表和.putdata()。这里有一些代码来测试这3种不同的方法。

from PIL import Image
from random import seed, randint

width, height = 200, 200
background = 0

seed(42)
d = dict(((x, y), randint(0, 255)) for x in range(width) for y in range(height))

algorithm = 2
print('Algorithm', algorithm)

if algorithm == 0:
    im = Image.new('L', (width, height))
    for i in d:
        im.putpixel(i, d[i])
elif algorithm == 1:
    buff = bytearray((background for _ in xrange(width * height)))
    for (x,y), v in d.items():
        buff[y*width + x] = v
    im = Image.frombytes('L', (width,height), str(buff))
elif algorithm == 2:
    data = [background] * width * height
    for i in d:
        x, y = i
        data[x + y * width] = d[i]
    im = Image.new('L', (width, height))
    im.putdata(data)

#im.show()

fname = 'qrand%d.png' % algorithm
im.save(fname)
print(fname, 'saved')

以下是运行Python 2.6.6的2GHz机器的典型时序

$ time ./qtest.py
Algorithm 0
qrand0.png saved

real    0m0.926s
user    0m0.768s
sys     0m0.040s

$ time ./qtest.py
Algorithm 1
qrand1.png saved

real    0m0.733s
user    0m0.548s
sys     0m0.020s

$ time ./qtest.py
Algorithm 2
qrand2.png saved

real    0m0.638s
user    0m0.520s
sys     0m0.032s