10

This script in the Python console:

>>> pixels = D.images[-1].pixels
>>> len(pixels)
8294400

>>> for i in range(64):
...     dummy = pixels[i]
...
>>>

takes over two seconds to run the for loop.

However, running pixels = [0 for i in range(len(pixels))] before the for loop causes the script to finish instantly.

What's going on with the Blender Python image pixel access, and how can I speed it up?

wchargin
  • 9,452
  • 5
  • 41
  • 66
  • 1
    I just tested CoDEmanX's code in blender2.71 and this does not work. pixels=img.pixels[:] returns a tuple which is not editable. I had to use list(img.pixels) to do some pixel tweaking. – Greg Sep 12 '14 at 13:41

1 Answers1

14

.pixels is a python object and pretty slow, especially if you change pixels. That is 'cause the entire buffer / python object is re-created for every single change (if you do it in a python loop). Not sure why it's that slow on read-only actions though...

You can speed it up tremendously if you cast it to a native python type (tuple) and use that copy instead:

img = bpy.data.images['Untitled']

pixels = img.pixels[:] # create a copy (tuple) for read-only access
# -- OR --
pixels = list(img.pixels) # create an editable copy (list)

# Use the tuple object, which is way faster than direct access to Image.pixels
for i in range(0, len(pixels), 4):
    pixels[i] = 1.0 - pixels[i] # invert red channel

# Write back to image.
# Slice notation here means to replace in-place, not sure if it's faster...
img.pixels[:] = pixels

# Should probably update image
img.update()
CodeManX
  • 29,298
  • 3
  • 89
  • 128
  • Thanks. I was casting with list(img.pixels) for temporary speedup, but this looks better. As a side note, would random access to this pixels = img.pixels[:] be decently fast? – wchargin Nov 03 '13 at 23:51
  • You can use a tuple copy if you need to read pixel values only, and cast to list if it needs to be editable. Both variants are very fast, and writing a modified copy back to Image.pixels is performing well too. Only direct access to .pixels is extremely slow. – CodeManX Jul 20 '15 at 12:33
  • Legendary comment, wow. 10 years old and still applies. I'm using it to set an asset browser thumbnail, which took like 5 seconds for a 128x128 image before, but is now instant. Using the slice notation on asset.preview.image_pixels_float is MOST DEFINITELY faster. Thank you so much. edit: 10 years EXACTLY ha. – MACHIN3 Nov 03 '23 at 18:29
  • @MACHIN3 Cheers, glad it's still helpful. It's somewhat unreal to get notifications about posts I have long forgotten about. Kudos on the timing as well! – CodeManX Nov 03 '23 at 21:35