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

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.