[英]What is the fastest way to draw an image from discrete pixel values in Python?
I wish to draw an image based on computed pixel values, as a means to visualize some data.我希望根据计算出的像素值绘制图像,作为可视化某些数据的一种方式。 Essentially, I wish to take a 2-dimensional matrix of color triplets and render it.
本质上,我希望采用彩色三元组的二维矩阵并渲染它。
Do note that this is not image processing, since I'm not transforming an existing image nor doing any sort of whole-image transformations, and it's also not vector graphics as there is no pre-determined structure to the image I'm rendering- I'm probably going to be producing amorphous blobs of color one pixel at a time.请注意,这不是图像处理,因为我没有转换现有图像,也没有进行任何类型的整体图像转换,而且它也不是矢量图形,因为我正在渲染的图像没有预先确定的结构-我可能会一次生成一个像素的无定形颜色斑点。
I need to render images about 1kx1k pixels for now, but something scalable would be useful.我现在需要渲染大约 1kx1k 像素的图像,但是可扩展的东西会很有用。 Final target format is PNG or any other lossless format.
最终目标格式是 PNG 或任何其他无损格式。
I've been using PIL at the moment via ImageDraw's draw.point , and I was wondering, given the very specific and relatively basic features I require, is there any faster library available?目前我一直在通过 ImageDraw 的 draw.point 使用 PIL,我想知道,鉴于我需要非常具体和相对基本的功能,是否有任何更快的库可用?
If you have numpy
and scipy
available (and if you are manipulating large arrays in Python, I would recommend them), then the scipy.misc.pilutil.toimage
function is very handy.如果您有可用的
numpy
和scipy
(并且如果您在 Python 中操作大型数组,我会推荐它们),那么scipy.misc.pilutil.toimage
函数非常方便。 A simple example:一个简单的例子:
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
The nice thing is toimage
copes with different data types very well, so a 2D array of floating-point numbers gets sensibly converted to grayscale etc. toimage
是toimage
可以很好地处理不同的数据类型,因此浮点数的二维数组被明智地转换为灰度等。
You can download numpy
and scipy
from here .你可以从这里下载
numpy
和scipy
。 Or using pip:或者使用 pip:
pip install numpy scipy
import Image
im= Image.new('RGB', (1024, 1024))
im.putdata([(255,0,0), (0,255,0), (0,0,255)])
im.save('test.png')
Puts a red, green and blue pixel in the top-left of the image.在图像的左上角放置一个红色、绿色和蓝色像素。
im.fromstring()
is faster still if you prefer to deal with byte values.如果您更喜欢处理字节值,
im.fromstring()
仍然更快。
For this example, install Numpy and Pillow .对于此示例,安装Numpy和Pillow 。
The goal is to first represent the image you want to create as an array arrays of sets of 3 (RGB) numbers - use Numpy's array()
, for performance and simplicity:目标是首先将要创建的图像表示为一组 3 (RGB) 数字集的数组数组 - 使用 Numpy 的
array()
,以提高性能和简单性:
import numpy
data = numpy.zeros((1024, 1024, 3), dtype=numpy.uint8)
Now, set the middle 3 pixels' RGB values to red, green, and blue:现在,将中间 3 个像素的 RGB 值设置为红色、绿色和蓝色:
data[512, 511] = [255, 0, 0]
data[512, 512] = [0, 255, 0]
data[512, 513] = [0, 0, 255]
Then, use Pillow's Image.fromarray()
to generate an Image from the array:然后,使用 Pillow 的
Image.fromarray()
从数组生成图像:
from PIL import Image
image = Image.fromarray(data)
Now, "show" the image (on OS X, this will open it as a temp-file in Preview):现在,“显示”图像(在 OS X 上,这将在预览中将其作为临时文件打开):
image.show()
This answer was inspired by BADCODE's answer, which was too out of date to use and too different to simply update without completely rewriting.这个答案的灵感来自 BADCODE 的答案,这个答案已经过时了,无法使用,也太不同了,不能简单地更新而不完全重写。
A different approach is to use Pyxel , an open source implementation of the TIC-80 API in Python3 (TIC-80 is the open source PICO-8).一种不同的方法是使用Pyxel ,它是Python3 中TIC-80 API 的开源实现(TIC-80 是开源 PICO-8)。
Here's a complete app that just draws one yellow pixel on a black background:这是一个完整的应用程序,它只在黑色背景上绘制一个黄色像素:
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)
Note : The library only allows for up to sixteen colors, but you can change which colors, and you could probably get it to support more without too much work.注意:该库最多只允许 16 种颜色,但是您可以更改哪些颜色,并且您可能无需太多工作就可以让它支持更多颜色。
I think you use PIL to generate an image file on the disk, and you later load it with an image reader software.我想你使用PIL在磁盘上生成一个图像文件,然后你用一个图像阅读器软件加载它。
You should get a small speed improvement by rendering directly the picture in memory (you will save the cost of writing the image on the disk and then re-loading it).您应该通过直接在内存中渲染图片来获得小的速度提升(您将节省将图像写入磁盘然后重新加载的成本)。 Have a look at this thread https://stackoverflow.com/questions/326300/python-best-library-for-drawing for how to render that image with various python modules.
查看此线程https://stackoverflow.com/questions/326300/python-best-library-for-drawing了解如何使用各种 python 模块渲染该图像。
I would personally try wxpython and the dc.DrawBitmap function.我会亲自尝试 wxpython 和dc.DrawBitmap函数。 If you use such a module rather than an external image reader you will have many benefits:
如果您使用这样的模块而不是外部图像阅读器,您将获得许多好处:
You can use the turtle
module if you don't want to install external modules.如果不想安装外部模块,可以使用
turtle
模块。 I created some useful functions:我创建了一些有用的函数:
setwindowsize( x,y )
- sets the window size to x*y setwindowsize( x,y )
- 将窗口大小设置为 x*ydrawpixel( x, y, (r,g,b), pixelsize)
- draws a pixel to x:y coordinates with an RGB color (tuple), with pixelsize thickness drawpixel( x, y, (r,g,b), pixelsize)
- 使用 RGB 颜色(元组)将像素绘制到 x:y 坐标,像素大小的厚度showimage()
- displays image 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()
Examples:例子:
200x200 window, 1 red pixel in the center 200x200 窗口,中心有 1 个红色像素
setwindowsize(200, 200)
drawpixel(100, 100, (255,0,0) )
showimage()
30x30 random colors. 30x30 随机颜色。 Pixel size: 10
像素大小: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()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.