4
$\begingroup$

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?

$\endgroup$
2
  • $\begingroup$ 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 $\endgroup$
    – Gorgious
    Feb 2, 2022 at 9:31
  • $\begingroup$ @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 $\endgroup$
    – simone
    Feb 2, 2022 at 10:14

1 Answer 1

7
$\begingroup$

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

$\endgroup$
4
  • $\begingroup$ 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? $\endgroup$
    – simone
    Feb 2, 2022 at 15:03
  • $\begingroup$ 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? $\endgroup$
    – simone
    Feb 2, 2022 at 15:12
  • $\begingroup$ Are you using a packed image or an external image ? $\endgroup$
    – Gorgious
    Feb 2, 2022 at 16:07
  • $\begingroup$ I am using a packed image. Checked using img.packed_file $\endgroup$
    – simone
    Feb 2, 2022 at 17:06

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .