Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Extract RGB and depth channels from exr images.
import numpy as np
import OpenEXR as exr
import Imath
def readEXR(filename):
"""Read color + depth data from EXR image file.
Parameters
----------
filename : str
File path.
Returns
-------
img : RGB or RGBA image in float32 format. Each color channel
lies within the interval [0, 1].
Color conversion from linear RGB to standard RGB is performed
internally. See https://en.wikipedia.org/wiki/SRGB#The_forward_transformation_(CIE_XYZ_to_sRGB)
for more information.
Z : Depth buffer in float32 format or None if the EXR file has no Z channel.
"""
exrfile = exr.InputFile(filename)
header = exrfile.header()
dw = header['dataWindow']
isize = (dw.max.y - dw.min.y + 1, dw.max.x - dw.min.x + 1)
channelData = dict()
# convert all channels in the image to numpy arrays
for c in header['channels']:
C = exrfile.channel(c, Imath.PixelType(Imath.PixelType.FLOAT))
C = np.fromstring(C, dtype=np.float32)
C = np.reshape(C, isize)
channelData[c] = C
colorChannels = ['R', 'G', 'B', 'A'] if 'A' in header['channels'] else ['R', 'G', 'B']
img = np.concatenate([channelData[c][...,np.newaxis] for c in colorChannels], axis=2)
# linear to standard RGB
img[..., :3] = np.where(img[..., :3] <= 0.0031308,
12.92 * img[..., :3],
1.055 * np.power(img[..., :3], 1 / 2.4) - 0.055)
# sanitize image to be in range [0, 1]
img = np.where(img < 0.0, 0.0, np.where(img > 1.0, 1, img))
Z = None if 'Z' not in header['channels'] else channelData['Z']
return img, Z
@christian-rauch
Copy link

christian-rauch commented Mar 30, 2020

It is likely that you will have to convert the colour into the sRGB space (https://en.wikipedia.org/wiki/SRGB#The_forward_transformation_(CIE_XYZ_to_sRGB))

def get_exr_rgb(path):
    I = OpenEXR.InputFile(path)
    dw = I.header()['displayWindow']
    size = (dw.max.y - dw.min.y + 1, dw.max.x - dw.min.x + 1)
    data = [np.fromstring(c, np.float32).reshape(size) for c in I.channels('RGB', Imath.PixelType(Imath.PixelType.FLOAT))]
    img = np.dstack(data)
    img = np.clip(img, 0, 1)
    # convert colour to sRGB
    img = np.where(img<=0.0031308, 12.92*img, 1.055*np.power(img, 1/2.4) - 0.055)
    return (img*255).astype(np.uint8)

@jadarve
Copy link
Author

jadarve commented Mar 30, 2020

Good call, thanks! I will update the Gist.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment