Skip to content

Instantly share code, notes, and snippets.

@jadarve
Last active August 20, 2024 07:18
Show Gist options
  • Save jadarve/de3815874d062f72eaf230a7df41771b to your computer and use it in GitHub Desktop.
Save jadarve/de3815874d062f72eaf230a7df41771b to your computer and use it in GitHub Desktop.
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

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.

@monolithMktg
Copy link

monolithMktg commented Aug 8, 2024

Thanks for the script I am looking to convert the EXR into 32bit RGBE.PNG file, not in sRGB. Please let me know what needs to be done?

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