15
$\begingroup$

Render Result exists in bpy.data.images["Render Result"] but it contains no data.

Also bpy.data.images["Render Result"].size[0] is 0, even if the render shows as an image in the UV/Image Editor with a width of 1366.

Maybe the render result cannot be accessed as an image or I missing some update or refresh call somewhere but I can't find such a thing in the 2.68 API documentation.

Any tip in the correct direction appreciated.

$\endgroup$
12
$\begingroup$

unfortunately accessing render results cannot be done via bpy.data.images['Render Result'].

There is a workaround by using Viewer node. basically you will need to attach a Viewer node to your render layer and then access pixels of the Viewer.

see this link: https://ammous88.wordpress.com/2015/01/16/blender-access-render-results-pixels-directly-from-python-2/

$\endgroup$
  • $\begingroup$ Give me some time to try it and see if it works better than my proposed solution. $\endgroup$ – Hatoru Hansou Jan 16 '15 at 22:40
  • $\begingroup$ The viewer node trick worked and saves me from having to create a temp file on disk. In my case, I have customized nodes and cannot lose them so I'm not doing the node clear step. I created the Viewer Node in the editor not in code, but the important thing here is that sending the output to the Viewer Node works. $\endgroup$ – Hatoru Hansou Jan 18 '15 at 1:47
  • $\begingroup$ indeed it does the job $\endgroup$ – wsfax Jan 18 '15 at 23:56
  • $\begingroup$ the only drawback is that pixels will always contain rgba even if you set your output to be rgb $\endgroup$ – wsfax Jan 19 '15 at 0:01
4
$\begingroup$

Answering myself, if somebody find a better solution please answer and I will change my accepted answer.

The only reliable way to access the render result pixels is this:

  1. Save the actual value of bpy.data.scenes["Scene"].render.filepath to a local variable

  2. Set bpy.data.scenes["Scene"].render.filepath to something to avoid overwriting any previous render, for example "//temp." + str(time.time()) + ".png". 1 and 2 can be ignored if you don't care of any previous render.

  3. Call bpy.ops.render.render(write_still=True). write_still set to true will cause the file to be immediately written to disk.

  4. Create a new image and load that file from disk, or use an existing image reserved for this purpose in your blend file and set its filepath and then reload.

  5. Do what you need to do with the loaded image pixels.

  6. Remove the loaded image, except you have a good reason to keep it in the blend file.

  7. Restore the original value of bpy.data.scenes["Scene"].render.filepath

Brief: the only reliable way to access pixel data of a render is to render it, save to disk immediately, recover from disk, read pixel data.

At the time of writing this, Blender version is 2.68.

$\endgroup$
2
$\begingroup$

Last time I experimented with this, it was necessary to save the content of Render Result as an image to disk and then load it as a new image. Then the pixel array is accessible. Maybe this API feature can be improved, or i'm doing it wrong :)

import bpy

bpy.data.images['Render Result'].save_render("somefile.tga")
r2 = bpy.data.images.load("somefile.tga")
r2.pixels[0] = 0.2345
$\endgroup$
  • $\begingroup$ Thank you. Indeed, pixel data is accessible if the image has a file path and is saved first. But the render I want to read from is generated by the script (by calling bpy.ops.render()). If I render with F12, assign a file path to the render result and save, the next time I call bpy.ops.render() Blender generated a new image called "Render Result.001", It does not use the "Render Result" image any more. $\endgroup$ – Hatoru Hansou Aug 6 '13 at 21:09
  • $\begingroup$ yeah, i'm going to avoid suggesting that you keep track of All images with string "Render Result" and sort them and access the last index -1, perhaps someone else can offer enlightenment. $\endgroup$ – zeffii Aug 6 '13 at 21:14
1
$\begingroup$

This might help..

RENDERING :

bpy.data.scenes['Scene'].render.filepath='file1' # directory and name
bpy.data.scenes['Scene'].render.resolution_x=width
bpy.data.scenes['Scene'].render.resolution_y=height
bpy.data.scenes['Scene'].render.pixel_aspect_x=1.0
bpy.data.scenes['Scene'].render.pixel_aspect_y=1.0

IMAGES :

image=bpy.data.images['image02'] # image02 as seen in uv editor
imageR=bpy.data.images['Render Result'] # useless, so bad
width=image.size[0]
height=image.size[1]

PIXELS=[0.0 for i in range(len(image.pixels))]
# len(image.pixels) == width * height * 3 ( or 4 with the alpha channel )

# here, work with PIXELS
image.pixels=PIXELS
$\endgroup$
1
$\begingroup$

Yet another workaround is to bake to an Image type texture, as long as you are not after the rendered result from the camera but the rendered surface of an object.

Then you can access the image pixels from Python like any other.

$\endgroup$
  • 1
    $\begingroup$ If memory serves me, what I was trying to do is using a 3D model to render different camera angles to a sprite sheet, because I don't know a way to copy a portion of an image from one image to another using only the Blender Python API and standard python APIs without adding something else to the mix, I needed to read pixels from the render result to copy a part of the render to the sprite sheet png (pixel by pixel, performance was not important). Yes, I needed the camera transformations. But thank you for the info. $\endgroup$ – Hatoru Hansou Jul 5 '17 at 22:56

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.