4

As an intermediate step for further evolution I am trying to edit the pixels of an image via Numpy, like this:

for img in bpy.data.images:
    print(img.name, img.size[1], img.size[0], img.channels, img.type, img.colorspace_settings)
img_arr = (np.array(img.pixels[:]) * 64).reshape((img.size[1], img.size[0], img.channels)) 
print('begin write to pixels')
# tried different things here
img.pixels = img_arr.flatten()
img.update()
print('image updated')

if img_arr.shape[0] and img_arr.shape[1]:
    # output image via OpenCV
    img_arr = cv2.cvtColor(np.float32(img_arr), cv2.COLOR_RGB2BGR)
    cv2.imwrite('out_cv2_' + str(i)  + '.png', img_arr)

    # direct save of image
    img.filepath = 'out_direct_' + str(i)  + '.png'
    img.file_format = 'PNG'
    img.save()
    i = i + 1

My expectation is that the image in Blender would be darkened, and more transparent. However that is not happening. The images I save via OpenCV for comparison are darker and semi-transparent.

I've tried different ways of writing to the pixels

  • divide the numpy array by 255
  • transofrm the numpy array into a tuple with np.asarray

What am I missing?

simone
  • 745
  • 4
  • 14
  • Do you reload the image in blender after saving it ? Because the image is not automatically reloaded everytime the file is changed in your disk. Also you can use foreach_get to populate numpy arrays very efficiently – Gorgious Feb 02 '22 at 09:31
  • @Gorgious - In my intention,nothing is written to disk, and everything happens in memory. The images written to disk in the question are just for comparing and checking that the transformation happens correctly – simone Feb 02 '22 at 10:14

1 Answers1

7

You can directly inspect the images in an Image Editor inside Blender. Here's a script example that will lower an image with random colors' $r, g, b$ channels and its transparency.

import bpy
import numpy as np
from random import random

resolution = (10, 10) img = bpy.data.images.get("Input") if img is None: img = bpy.data.images.new("Input", width=resolution[0], height=resolution[1]) values = img.size[0] * img.size[1] * 4 random_colors = [random() for v in range(values)] img.pixels.foreach_set(random_colors)

You can start your script here if you already have an external image loaded in

colors = np.empty(shape = values, dtype=np.float32) img.pixels.foreach_get(colors)

darkening = 0.8 transparency = 0.5

colors[0::4] = darkening colors[1::4] = darkening colors[2::4] = darkening colors[3::4] = transparency

output = bpy.data.images.get("Output") if output is None: output = bpy.data.images.new("Output", width=img.size[0], height=img.size[1]) output.pixels.foreach_set(colors)

Result :

enter image description here

Source : Read pixel color with foreach_get() on image data

Gorgious
  • 30,723
  • 2
  • 44
  • 101
  • Thanks - it kind of looks like this works, as when I save the images the edits are there. However they are not reflected in the materials that used the image that has been edited. Is that a different question? – simone Feb 02 '22 at 15:03
  • and is it possible that the message "Error: Unable to pack file, source path '/blah/blah/blah.png' not found ERROR: Image "/blah/blah/blah.png" not available. Keeping packed image" has something to do with that? – simone Feb 02 '22 at 15:12
  • Are you using a packed image or an external image ? – Gorgious Feb 02 '22 at 16:07
  • I am using a packed image. Checked using img.packed_file – simone Feb 02 '22 at 17:06