# Uninterpretablity in depth maps: why the pixel values do not necessarily represent a valid distance?

I am rendering depth maps from different angles for many meshes by placing my cameras on a sphere with fixed radius. The meshes I use are all normalized (all within a sphere with radius 0.5) and centered at (0, 0, 0). After rendering I load the depth maps in Python using imageio package or scipy.ndimage.imread I noticed that each individual depth map always has a maximum value of 255. However, what I actually expected was to obtain depth maps whose values are interpretable and intuitive. By interpretability I mean a distance of 40 in one depth map rendered from mesh X will be the same as distance 40 of another depth map rendered from mesh Y. But this is not the case as of now, even within the renderings of the same mesh. To make it more clear: if I have a very small mesh whose furthest vertex would be very close to (0, 0, 0) I would still have values of 255 in the rendered depth maps. However, I will still have pixel values of 255 in the depth map renderings of another mesh which is much larger than the previous one. The same issue persists if I normalize the output values of the Z-pass: all renderings have a maximum value of 1. I'm afraid the issue is related to the PNG saving pipeline that might be doing something weird to the rendering results, as discussed here. So I wonder does anyone know if I am doing something wrong? Any thoughts/solutions would be greatly appreciated.

FYI, here's the code I use for rendering:

scene = bpy.context.scene
scene.render.image_settings.color_depth = '16'
scene.display_settings.display_device = 'sRGB'
scene.view_settings.view_transform = 'Raw'
scene.sequencer_colorspace_settings.name = 'Raw'
scene.use_nodes = True
for node in scene.node_tree.nodes:
scene.node_tree.nodes.remove(node)
renderNode = scene.node_tree.nodes.new('CompositorNodeRLayers')

depthOutputNode = scene.node_tree.nodes.new('CompositorNodeOutputFile')
depthOutputNode.format.file_format = 'PNG'
depthOutputNode.format.color_depth = '16'
depthOutputNode.format.color_mode = 'RGB'
depthOutputNode.base_path = 'somePath/'
depthOutputNode.file_slots[0].path = 'fileNameDepth#'

bpy.ops.render.render(write_still=True)


Update: I just did file depthImg.png in Ubuntu and confirmed that the generated depth maps are 16-bit. It's likely that the image packages in Python do not support reading png files with more than 8 bits per channel! I tried a couple of methods and non works. Any solutions for this?

• Can I suggest using Animation Nodes for this? One can simply use a BVH Tree to ray cast some rays and compute the distance. No images are required and it is reasonably fast. You can then continue processing in AN or pass the values to python. Mar 31, 2018 at 20:00
• Also, I haven't tried this, but wouldn't sampling the values from bpy.data.images[0].pixels work? I think Float Buffer have to be enabled to get non normalized values. Mar 31, 2018 at 20:02
• @OmarAhmad I have never used animation nodes so I'm not sure if that's the way to go. I just actually confirmed that the stored PNGs are 16-bits. But it seems that almost no image package in Python reads 16-bit PNGs! So it could just be a reading issue. I tried storing the original pixel values but I hit lots of obstacles and I eventually realized that reading pixel values is impossible unless Blender fixes a bug (see here).
– Amir
Mar 31, 2018 at 20:07
• Stop using PNGs. They are junk. Depth is data, and no display referred encoding format is going to make this easy. Just use EXRs. Mar 31, 2018 at 20:13
• It seems to me like you keep asking the same question many times... The Z pass is not an image, it should be thought as data. If you need to visualize it, use a normalize node, but do not save that. Saving in a display referred format will mean scaling and possibly distorting the information. Keep the Z pass as linear, unscaled data in an EXR file.
– user1853
Mar 31, 2018 at 23:06

As @troy_s suggested, PNGs are not suitable for this use. PNGs are more suited to image color data only. For depth information you should use a format such as Open EXR. This can be achieved easily by simply changing the depthOutputNode.format.file_format = 'PNG' line to depthOutputNode.format.file_format = 'OPEN_EXR'.