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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.