What is the fastest way to draw an image from discrete pixel values in Python?

前端 未结 5 1850
时光取名叫无心
时光取名叫无心 2020-12-07 18:41

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

相关标签:
5条回答
  • 2020-12-07 19:19

    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
    0 讨论(0)
  • 2020-12-07 19:22

    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.

    0 讨论(0)
  • 2020-12-07 19:26

    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
    
    0 讨论(0)
  • 2020-12-07 19:28

    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.

    0 讨论(0)
  • 2020-12-07 19:34
    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.

    0 讨论(0)
提交回复
热议问题