Skip to content

Instantly share code, notes, and snippets.

@arseniy-panfilov
Last active March 22, 2024 13:10
Show Gist options
  • Save arseniy-panfilov/4dc8fc5131277affe64619b1a9d00da0 to your computer and use it in GitHub Desktop.
Save arseniy-panfilov/4dc8fc5131277affe64619b1a9d00da0 to your computer and use it in GitHub Desktop.
Convert .EXR image to pillow's `Image` with gamma encoding
from PIL import Image
import OpenEXR
import Imath
import numpy
import numexpr as ne
FLOAT = Imath.PixelType(Imath.PixelType.FLOAT)
def exr_to_array(exrfile):
file = OpenEXR.InputFile(exrfile)
dw = file.header()['dataWindow']
channels = list(file.header()['channels'].keys())
channels_list = [c for c in ('R', 'G', 'B', 'A') if c in channels]
size = (dw.max.x - dw.min.x + 1, dw.max.y - dw.min.y + 1)
color_channels = file.channels(channels_list, FLOAT)
channels_tuple = [numpy.frombuffer(channel, dtype='f') for channel in color_channels]
return numpy.dstack(channels_tuple).reshape(size + (len(channels_tuple),))
def encode_to_srgb(x):
a = 0.055
return ne.evaluate("""where(
x <= 0.0031308,
x * 12.92,
(1 + a) * (x ** (1 / 2.4)) - a
)""")
def exr_to_srgb(exrfile):
array = exr_to_array(exrfile)
result = encode_to_srgb(array) * 255.
present_channels = ["R", "G", "B", "A"][:result.shape[2]]
channels = "".join(present_channels)
return Image.fromarray(result.astype('uint8'), channels)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment