从 Blender 中的查看器节点检索的像素比实际渲染的图像更暗......为什么?

问题描述

我正在尝试创建一个管道,在该管道中我首先使用 Blender python API(我使用 Blender 2.90)渲染图像,然后在 python 中执行一些图像处理。我想直接从 Blender 获取图像,而不是先将渲染的图像写入磁盘然后再次加载它。我在搅拌机 GUI 中运行了以下代码

import bpy
import numpy as np
import PIL.Image as Image 
from skimage.util import img_as_ubyte 

resolution_x = 512
resolution_y = 512

# render settings
scene = bpy.context.scene
scene.render.engine = 'BLENDER_EEVEE'
scene.render.resolution_x = resolution_x
scene.render.resolution_y = resolution_y
scene.render.image_settings.file_format = 'PNG'
scene.render.filepath = "path/to/good_image.png"

# create Viewer Layer in Compositor
scene.use_nodes = True
tree = scene.node_tree 
nodes = tree.nodes
links = tree.links

for node in nodes:
    nodes.remove(node)

render_layer_node = nodes.new('CompositorNodeRLayers')
viewer_node = nodes.new('CompositorNodeViewer')

links.new(viewer_node.inputs[0],render_layer_node.outputs[0])

# render scene and get pixels from Viewer Node
bpy.ops.render.render(write_still=True) 
pixels = bpy.data.images['Viewer Node'].pixels

# do some processing and save
img = np.flip(img_as_ubyte(np.array(pixels[:]).reshape((resolution_y,resolution_x,4))),axis=0)
Image.fromarray(img).save("path/to/bad_image.png")

问题:我从查看器节点获得的图像比以传统方式保存的图像 (bad image) 暗得多 (good image)。有谁知道为什么会发生这种情况以及如何解决它? Blender 处理像素值的方式可能与我预期的不同吗?

一些附加信息: 在转换为 uint8 之前,暗图像中 alpha 通道的值为 1.0(它们实际上应该是)。暗图像中的背景值不是 0.0 或负值(从外观上可能会猜到),而是 0.05...

我尝试过的: 我认为像素可能会在 -1 到 1 的范围内缩放,所以我在转换为 uint8 之前将像素重新缩放到 0 到 1 的范围......也没有导致正确的图像:(

解决方法

这是因为您从 Viewer Node 获得的图像是在进行颜色管理之前“直接来自合成”的图像。您可以查看文档 here:此图像仍在线性空间中。

另一方面,您的 good_image.png 是在转换为“显示空间”后获得的(参见文档中的图表)。因此它被转换成对数空间,也许是伽马校正等。

最后,您可以通过调用 bpy.data.images['Viewer Node'].save_render(filepath) 从查看器节点获取接近(但略有不同)良好图像的图像,但无法直接提取颜色管理版本无需先渲染到文件。您可以通过将 PyOpenColorIO 添加到脚本并应用此模块中的颜色管理来自己完成。