7

I read some article how to get the z-Depth values from the Viewer Node. So i created a scene with a camera and a Plane with distance z=2. Then i tried to get RGB values and also z-Depth with compositing Nodes.

Code from my Plugin:

bpy.context.scene.render.use_compositing = True
bpy.context.scene.use_nodes = True
tree = bpy.context.scene.node_tree
links = tree.links
for n in tree.nodes:
    tree.nodes.remove(n)
rl = tree.nodes.new('CompositorNodeRLayers')      
viewer = tree.nodes.new('CompositorNodeViewer')   
viewer.use_alpha = False
links.new(rl.outputs[0], viewer.inputs[0])  # link Image output to Viewer input

# render and get result
bpy.ops.render.render()
links.new(rl.outputs[0], viewer.inputs[0])  # link Image output to Viewer input
pixels = bpy.data.images['Viewer Node'].pixels
print(pixels[0])
arr = np.array(pixels[:])
arr = np.delete(arr, np.arange(3, arr.size, 4)) # delete alpha
arr = arr.reshape((height,width,3))

# save z-depth 
links.new(rl.outputs[2], viewer.inputs[0])  # link Image output to Viewer input
bpy.ops.image.reload()
pixelsZ = bpy.data.images['Viewer Node'].pixels
print(pixelsZ[0])
arrZ = np.array(pixels[:])[::4] # every 4th px

Both pixel arrays are the same. I tried this also manually and there it works perfectly. I thought about refreshing the image (in the image editor it refreshs the Viewer Node automatically when i change the node links), but even this didn't work.

Have anybody an idea how to fix this or what i'm doing wrong?

edit: I think i got the problem: I have to render again, after changing the nodes. is there an option to change and read the information without rerendering?

vtni
  • 281
  • 3
  • 8
  • 2
    This may be a dumb question, but are you actually rendering the Z depth pass? You won't be able to access it via compositing if it's not been rendered. – Todd McIntosh Aug 06 '15 at 13:16
  • Where can i check this? If i connect output Z of RenderLayer to my Image input of ViewerNode and check the Image "Viewer Node" the RGB values are the same and match the Z-Depth (R=G=B ~ 2). – vtni Aug 06 '15 at 13:21
  • Can you output the zdepth pass to disk, just to check that it's being created properly? – Todd McIntosh Aug 06 '15 at 13:24
  • Use a File Output node to save the Z pass to disk. – Todd McIntosh Aug 06 '15 at 13:25
  • Also, once you run this script (maybe independently of your addon context), you should see the appropriate node setup in the compositor. You should be able to check if the Z depth pass is in there manually. – Todd McIntosh Aug 06 '15 at 13:27
  • The file output does work (UI), but values above 1 are clipped. After running my plugin the nodes and links are correct, but the pixel values aren't. – vtni Aug 06 '15 at 13:37
  • to properly save the Z depth information you need to use a format like OpenEXR that can accept values larger than one. –  Aug 06 '15 at 15:04
  • i have found my error (you must rerender after changing nodes), but until now i have no solution. i can't save the images on disk, i need to get them without saving. – vtni Aug 06 '15 at 15:20
  • Hmm, you should not have to re-render to get the Z depth info. The first render should be storing all the render passes in a temp EXR file (Blender's internal frame buffer), which means the Z depth pass already exists. – Todd McIntosh Aug 06 '15 at 16:25
  • Yes, i thought the same and it worked with the blender UI. But the code in my plugin didn't get the z depth information without rerendering. – vtni Aug 06 '15 at 21:24

1 Answers1

7

I am trying to do something similar. I (think) I made it by connecting the Render Image to Viewer Image and by connecting Render Z to Viewer Alpha. I used your code as a starting point.

import bpy
import numpy as np

bpy.context.scene.render.use_compositing = True
bpy.context.scene.use_nodes = True
tree = bpy.context.scene.node_tree
links = tree.links

for n in tree.nodes:
    tree.nodes.remove(n)
rl = tree.nodes.new('CompositorNodeRLayers')      

vl = tree.nodes.new('CompositorNodeViewer')   
vl.use_alpha = True
links.new(rl.outputs[0], vl.inputs[0])  # link Renger Image to Viewer Image
links.new(rl.outputs[2], vl.inputs[1])  # link Render Z to Viewer Alpha

#render
bpy.context.scene.render.resolution_percentage = 100 #make sure scene height and width are ok (edit)
bpy.ops.render.render()

#get the pixels and put them into a numpy array
pixels = np.array(bpy.data.images['Viewer Node'].pixels)
print(len(pixels))

width = bpy.context.scene.render.resolution_x 
height = bpy.context.scene.render.resolution_y

#reshaping into image array 4 channel (rgbz)
image = pixels.reshape(height,width,4)

#depth analysis...
z = image[:,:,3]
zf = z[z<1000] #
print(np.min(zf),np.max(zf))

I wouldn't use Viewer Depth channel since Image pixels (RGBA) are floats whereas depth are ints.

user34565
  • 171
  • 1
  • 4
  • 1
    I am using code that is essentially the same, but my viewer node output is always of fixed size 256 x 256 (regardless of my settings) and all values are zero. Any idea how to fix this? (Using Blender 2.83) – aviator Sep 22 '20 at 01:48