在Python中,从离散像素值绘制图像的最快方法是什么?

50

我希望基于计算出的像素值绘制一幅图像,用作可视化某些数据的手段。本质上,我想要获取一 个由颜色三元组构成的二维矩阵并将其渲染。

请注意,这不是图像处理,因为我不是在转换现有图像,也不会进行任何整体图像转换,而且它也不是矢量图形,因为我正在渲染的图像没有预先确定的结构 - 我可能每次只是一个像素地生成无定形的颜色斑点。

目前我需要渲染大约1kx1k像素的图像,但可扩展性更高的东西将非常有用。最终目标格式为PNG或任何其他无损格式。

目前我一直在使用PIL,通过ImageDraw的draw.point方法来实现。考虑到我所需的非常特定和相对基本的功能,是否有更快的库可供使用呢?

6个回答

40
如果你有numpyscipy(如果你在Python中处理大数组,我建议你使用它们),那么scipy.misc.pilutil.toimage函数非常方便。 一个简单的例子:
import numpy as np
import scipy.misc as smp

# Create a 1024x1024x3 array of 8 bit unsigned integers
data = np.zeros( (1024,1024,3), dtype=np.uint8 )

data[512,512] = [254,0,0]       # Makes the middle pixel red
data[512,513] = [0,0,255]       # Makes the next pixel blue

img = smp.toimage( data )       # Create a PIL image
img.show()                      # View in default viewer

很好的一件事是,toimage 很好地处理不同的数据类型,因此浮点数的二维数组可以合理地转换成灰度等。

您可以从这里下载 numpyscipy。或者使用pip:

pip install numpy scipy

2
如果您在科学背景下进行此操作,还可以使用matplotlib.pyplot的"imshow"函数。它可以将色图和差值方法作为参数,并且一直为我所用。 - RodericDay
6
toimage现已被弃用:https://docs.scipy.org/doc/scipy/reference/generated/scipy.misc.toimage.html#scipy.misc.toimage - seddonym
如果我有许多像素??? 大约5K左右,这种情况下我的Python脚本会是什么样的??? - M. D. P
9
直接使用Pillow的Image.fromarray代替Scipy中的toimage。Scipy.misc模块没有'toimage'属性。(来源) - Daddy32
1
toimage 函数在 Scipy 1.3.0 版本中已被删除。因此,如果您想使用此解决方案,需要安装1.2.0版本。 - Dogu Deniz Ugur
显示剩余2条评论

24
import Image
im= Image.new('RGB', (1024, 1024))
im.putdata([(255,0,0), (0,255,0), (0,0,255)])
im.save('test.png')

在图像的左上角放置一个红、绿和蓝色的像素。

如果您更喜欢处理字节值,则使用im.fromstring()可以更快。


14
2017年的第一行代码是:从PIL库中导入Image模块。 - mountrix

9

要求

对于这个例子,需要安装NumpyPillow

示例

首先将要创建的图像表示为一组三个元素的数组集合(RGB数字)- 使用Numpy的array(),以获得更好的性能和简洁性:

import numpy

data = numpy.zeros((1024, 1024, 3), dtype=numpy.uint8)

现在,将中间3个像素的RGB值设置为红色、绿色和蓝色:
data[512, 511] = [255, 0, 0]
data[512, 512] = [0, 255, 0]
data[512, 513] = [0, 0, 255]

然后,使用Pillow的 Image.fromarray() 从数组中生成图像:
from PIL import Image

image = Image.fromarray(data)

现在,"显示"图片(在OS X上,这将在预览中以临时文件的形式打开它):
image.show()

注意

这个答案受到了BADCODE的启发,但是他的答案已经过时了,不能使用,并且更新起来也太不同了,必须完全重写。


2

另一种方法是使用Pyxel,这是Python3中TIC-80 API的开源实现(TIC-80是开源的PICO-8)。

以下是一个完整的应用程序,它只在黑色背景上绘制了一个黄色像素:

import pyxel

def update():

    """This function just maps the Q key to `pyxel.quit`,
    which works just like `sys.exit`."""

    if pyxel.btnp(pyxel.KEY_Q): pyxel.quit()

def draw():

    """This function clears the screen and draws a single
    pixel, whenever the buffer needs updating. Note that
    colors are specified as palette indexes (0-15)."""

    pyxel.cls(0)            # clear screen (color)
    pyxel.pix(10, 10, 10)   # blit a pixel (x, y, color)

pyxel.init(160, 120)        # initilize gui (width, height)
pyxel.run(update, draw)     # run the game  (*callbacks)

注意: 这个库只允许最多十六种颜色,但您可以更改这些颜色,并且可能不需要太多工作就可以支持更多颜色。


1

我认为你使用了PIL来生成一个磁盘上的图像文件,然后用图像阅读器软件加载它。

如果直接在内存中渲染图片(可以节省将图片写入磁盘并重新加载的时间),你会得到一些小的速度提升。可以查看这个帖子 https://stackoverflow.com/questions/326300/python-best-library-for-drawing ,了解如何使用各种Python模块来渲染图像。

个人建议尝试wxpython和dc.DrawBitmap函数。如果使用此模块而不是外部图像阅读器,则会有很多好处:

  • 速度快
  • 您将能够创建带有参数按钮的交互式用户界面。
  • 您将能够轻松编程缩放功能
  • 您将能够在计算图像时绘制它,如果计算时间很长,这可能非常有用

0
你可以使用 turtle 模块,如果你不想安装外部模块。我创建了一些有用的函数:
  • setwindowsize( x,y ) - 将窗口大小设置为 x*y
  • drawpixel( x, y, (r,g,b), pixelsize) - 使用 RGB 颜色(元组)和像素大小在 x:y 坐标处绘制像素
  • showimage() - 显示图像
import turtle

def setwindowsize(x=640, y=640):
    turtle.setup(x, y)
    turtle.setworldcoordinates(0,0,x,y)

def drawpixel(x, y, color, pixelsize = 1 ):
    turtle.tracer(0, 0)
    turtle.colormode(255)
    turtle.penup()
    turtle.setpos(x*pixelsize,y*pixelsize)
    turtle.color(color)
    turtle.pendown()
    turtle.begin_fill()
    for i in range(4):
        turtle.forward(pixelsize)
        turtle.right(90)
    turtle.end_fill()

def showimage():
    turtle.hideturtle()
    turtle.update()

范例:

200x200 的窗口,中心点有一个红色像素

setwindowsize(200, 200)
drawpixel(100, 100, (255,0,0) )
showimage()

enter image description here

30x30 随机颜色。像素大小:10

from random import *

setwindowsize(300,300)

for x in range(30):
    for y in range(30):
        color = (randint(0,255),randint(0,255),randint(0,255))
        drawpixel(x,y,color,10)
    
showimage()

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接