openexr-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Openexr-devel] Merging Multi Channel Layers


From: Aaron Carlisle
Subject: Re: [Openexr-devel] Merging Multi Channel Layers
Date: Wed, 9 Dec 2015 17:32:28 +0000

It's a little weird to explain, but basically the EXR renders used to render out into the alpha channel (since it was only black and white). This is fine since now you can just dump the rgb channels and everything is great, the problem now is that due to recent updates there is data being rendered in the rgb channels instead of the alpha channel (alpha is empty) and in some cases those channels contain different data (other than 1 or 0). What we did was merge the rgb data for a specific layer into one channel (as if all the data was stored in the alpha again) and then gave that channel a custom name "matte".  So (customLayer.blue, customLayer.green, customLayer.red) become (matte.customLayer). On the compositing side, when they open up the EXR in nuke all the channels that use to be there (customLayer.blue...) are all replaced with just one channel (matte.customLayer). That new channel contains all the pixel data that was stored in the old channels. So essentially, three channels become one. Basically, we're turning it into an alpha or an even better way to think about it is illumanence. 


The issue is this conversion takes way to long in Python and C++ has been a bit harder to figure out. I'm not sure how to do the same conversion in C++. With Python it was basically just a series of collecting the rgb channels for each layer, grabbing the pixelData for those layers, using array.array to convert it into a string set then assigning a new layer/channel to that collection of data and re-storing that back into the header of the file and writing out the new pixels.


here's the python code

#!/usr/bin/python

import OpenEXR
import re
import os
import array
import Imath
import time

CHANNEL_MATCH = re.compile('([a-z0-9_]+)\.([rdgrnblue]+)', re.I)
ALPHA_MATCH = re.compile('([a-z0-9_]+)\.([a]+)', re.I)
HALF = Imath.Channel(Imath.PixelType(Imath.PixelType.HALF))

def matte_pass_channel_cleanup(exr_file = '/path/to/exr/image.exr​'):
    start = time.time()

    if os.path.exists(exr_file) and OpenEXR.isOpenExrFile(exr_file):
        channels_to_merge = defaultdict(list)
        base_channels = []

        # Read the file and header
        handle = OpenEXR.InputFile(exr_file)
        header = handle.header()
        # Get the channels (is a dict)
        channels = header['channels']

        header['channels'] = {}

        new_channels = {}
        for channel_name, channel_data in channels.iteritems():
            match = CHANNEL_MATCH.match(channel_name)
            if match:
                layer, channel = match.groups()
                channels_to_merge[layer].append(channel)

            elif not ALPHA_MATCH.match(channel_name):
                base_channels.append(channel_name)

        for layer in base_channels:
            all_pixels = array.array( 'f', handle.channel(layer, Imath.PixelType(Imath.PixelType.HALF))).tolist()
            new_channels[layer] = array.array('f', all_pixels).tostring()
            print layer

        for layer, data in channels_to_merge.iteritems():
            new_pixels = []

            # naming
            try:
                new_layer_name = layer.split('_')[1]
            except:
                new_layer_name = layer

            new_pixels = array.array('f', handle.channel('{0}.{1}'.format(layer, data[0])))
            new_channels['matte.{0}'.format(new_layer_name)] = array.array(
                'f', new_pixels).tostring()

        header['channels'] = dict([(c, HALF) for c in new_channels.keys()])
        out = OpenEXR.OutputFile('/path/to/exr/image.exr', header)
        out.writePixels(new_channels)

if __name__ == "__main__":
    matte_pass_channel_cleanup()​


Thanks!

-Aaron


From: Ari Rubenstein <address@hidden>
Sent: Wednesday, December 9, 2015 7:31 AM
To: Aaron Carlisle
Cc: address@hidden; Ari Rubenstein
Subject: Re: [Openexr-devel] Merging Multi Channel Layers
 
Aaron,

I'm not a programmer, but coming at it from the end user of exr multi-channel files in compositing ... I'm curious how you'd intend to merge the 4-part channel down into 1 and how the end user would be able to split out individual channels within Nuke ?
Compositors access the individual channels for all sorts purposes in editing and look development.

not sure why  the exr's would be black and white except that when you view individual channels (R G B) separately they do appear greyscale. 


--
Ari Rubenstein
Lead Compositor
www.blueskystudios.com



From: "Aaron Carlisle" <address@hidden>
To: address@hidden
Sent: Tuesday, December 8, 2015 5:34:05 PM
Subject: [Openexr-devel] Merging Multi Channel Layers

Hi!

Not sure if this is the right place to reach out, but I'm trying to take
an EXR image and merge the channels in each layer down to one. Currently
there are multiple channels for one layer (test.alpha, test.red,
test.green, test.blue) but the EXR's that are being rendered out are
black and white and all the pixel data is being stored in the RGB
channels. In nuke there are channel limits and we're trying not to reach
that (we have ran into that issue in the past).

I was able to accomplish this in Python, so that when the script is ran
it takes the EXR and basically sums up all the pixel data for each of
the RGB channels in the layer into one, then writes it back out with a
custom name (matte.whateverTheLayerWasCalled). This works great accept
it's incredibly slow. So, I'm porting it to C++ but I'm struggling a
little bit on the best way to handle this.

I was wondering if anyone could help provide a generic example solution
or maybe some tips.

All the best!
-Aaron

If you'd like to see the Python/C++ code just let me know.

_______________________________________________
Openexr-devel mailing list
address@hidden
https://lists.nongnu.org/mailman/listinfo/openexr-devel


reply via email to

[Prev in Thread] Current Thread [Next in Thread]