I render surface Normals using Cycles and store the results in EXR format. The values in the EXR format are within the range of [-1, 1]
meaning that I cannot directly store the values in a PNG file. Here's how I read the .exr
files and store store the values in a numpy
array:
import OpenEXR, array, Imath
exrFile = OpenEXR.InputFile('normal.exr')
FLOAT = Imath.PixelType(Imath.PixelType.FLOAT)
(RGB) = [array.array('f', exrFile.channel(Chan, FLOAT)).tolist() for Chan in ("R", "G", "B") ]
normalNPArray = np.array(RGB)
normalNPArray = normalNPArray.reshape((3, resolution, resolution))
I normalize the values as follow and store the surface Normal as a PNG image:
normalNPArray += 1
normalNPArray /= 2
normalNPArray *= 255
normalNPArray = normalNPArray.astype(np.uint8)
im = Image.fromarray(normalNPArray.transpose(1, 2, 0), mode='RGB')
im.save('temp.png')
Here's what I get after opening the stored image:
If I simply ignore the values below zero (remove/comment the first two lines) I get the following:
However, if I directly store the surface Normal as a PNG image instead of EXR I get the following:
I wonder, how can I get a visualization that looks like the PNG rendering? How does Blender normalize the values?