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. Final target format is PNG or any other lossless format.

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?


Asked by: Clark850 | Posted: 28-01-2022






Answer 1

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. 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.

You can download numpy and scipy from here. Or using pip:

pip install numpy scipy

Answered by: Kellan821 | Posted: 01-03-2022



Answer 2

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.

Answered by: Maria337 | Posted: 01-03-2022



Answer 3

Requirements

For this example, install Numpy and Pillow.

Example

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:

import numpy

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

Now, set the middle 3 pixels' RGB values to red, green, and blue:

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:

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):

image.show()

Note

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.

Answered by: Blake681 | Posted: 01-03-2022



Answer 4

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).

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.

Answered by: Edward851 | Posted: 01-03-2022



Answer 5

I think you use PIL to generate an image file on the disk, and you later load it with an image reader software.

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.

I would personally try wxpython and the dc.DrawBitmap function. If you use such a module rather than an external image reader you will have many benefits:

  • speed
  • you will be able to create an interactive user interface with buttons for parameters.
  • you will be able to easily program a Zoomin and Zoomout function
  • you will be able to plot the image as you compute it, which can be quite useful if the computation takes a lot of time

Answered by: Dainton284 | Posted: 01-03-2022



Answer 6

You can use the turtle module if you don't want to install external modules. I created some useful functions:

  • setwindowsize( x,y ) - sets the window size to x*y
  • drawpixel( x, y, (r,g,b), pixelsize) - draws a pixel to x:y coordinates with an RGB color (tuple), with pixelsize thickness
  • showimage() - displays image
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

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

enter image description here

30x30 random colors. Pixel size: 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

Answered by: Marcus172 | Posted: 01-03-2022



Similar questions

python - find tangent vector at a point for discrete data points

I have a vector with a min of two points in space, e.g: A = np.array([-1452.18133319 3285.44737438 -7075.49516676]) B = np.array([-1452.20175668 3285.29632734 -7075.49110863]) I want to find the tangent of the vector at a discrete points along the curve, g.g the beginning and end of the curve. I know how to do it in Matlab but I want to do it in Python. This is the code in Matlab: ...


python - Align color fields and labels in discrete colorbar

I am trying to create a filled contour plot with discrete contour levels which I need to control in order to compare values from different data sources. I thought that this should be easily accomplished with fig.colorbar(c, ax=ax, ticks=my_levels). However, as you can see from the example below, something goes wrong with the alignment of colors and values, and I haven't been able to figure out what is wrong wi...


python - Find global minimum for discrete function

This is what my code looks like when simplified: # This function returns some value depending on the index (integer) # with which it is called. def funct(index): value <-- some_process[index] # Return value for this index. return value where the indexes allowed are stored in a list: # List if indexes. x = [0,1,2,3,...,1000] I need to find th...


python - Convert Numpy array into Orange table of discrete values

My problem is exactly what the title says: I have a numpy array of integers and wish to convert it into an Orange table with discrete values. If I follow these steps, it fails: import numpy as np import Orange a = np.arange(100).reshape((10,10)).astype(np.int8) fields = ('one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten') d = Orange.data.Domain([Orange.feature.Discrete(x) for x in...


python - Discrete colormap not working properly?

I have a range of values from 0 to ~450 and I want to make a discrete colormap where a range of values will always be represented by a particular colour. I'm defining my colours like this: red = np.array([0, 0, 221, 239, 235, 248, 239, 234, 228, 222, 205, 196, 161, 147, 126, 99, 87, 70, 61]) / 256. green = np.array([16, 217, 242, 240, 255, 225, 190, 160, 128, 87, 72, 59, 33, 21, 29, 30, 30, 29, 26])...


python - mayavi mapping a discrete colorbar on a surface

I want to change the color of a surface depending on another value (an ID) that takes discrete values (so I need a discrete colorbar). In the simplified example below I have drawn a sphere with 3 different IDs: 0/red on the left 2/blue on the middle 1/Green on the left But with the code below, I obtain some strange behaviours (green points) at the limit between red and blue. It is probably ...


python - Check if discrete signal is periodic (or close to), given discrete event times

So I have a list of times Z (see below) when a particular event happens. How can I see how close to periodic is this signal? I guess, I can find the pairwise time differences between serial events and see if it's an approximately steady quantity, but is there a pythonic way to do this? Z = [7.72, 10.9, 13.9, 16.69, 19.5, 22.31, 25.0, 27.69...]


python - Map discrete value to color by type and position

I asked how to map discrete value to color yesterday and got the following useful answer. Map discrete value to color I am trying to graph colors based on 4 discrete value 1, 2, 3, 4. I want to define 1 as black, 2 as red, 3 as yellow and 4 as green. does anyone know how to do it? You could try imshow...


python - Finding discrete logic levels in a waveform

I have some waveforms that I'm trying to process with Python. I would like to find discrete logic levels that these signals are displaying. I have a 1D array of each waveform's x and y values. The data looks something like this example staircase: How can I find the different levels? Here they might be around (1.8, 3.3), (2.1, 3.0), (2.7, 2.6...


python - How to use tkinter slider `Scale` widget with discrete steps?

Is it possible to have a slider (Scale widget in tkinter) where the possible values that are displayed when manipulating the slider are discrete values read from a list? The values in my list are not in even steps and are situation dependent. From all the examples I've seen, you can specify a minimum value, a maximum value and a step value (n values at a time), but my list might look like this:...






Still can't find your answer? Check out these communities...



PySlackers | Full Stack Python | NHS Python | Pythonist Cafe | Hacker Earth | Discord Python



top