So sorry for the delay in responding, this slipped through the cracks somehow. 
(Pro tip: it really is ok to send a second email after a couple days if nobody 
seems to respond. It usually just means I was really busy that day and then 
simply forgot to get back to it.)

I think you mostly have it figured out: An important simplification that 
ImageBuf makes is to internally store all channels as a single data format. If 
you read an exr that is mixed, like (half, half, float), into an ImageBuf, it 
will store internally as just float. But note that the 
imagebuf.nativespec().channelformats will still reveal the original per-channel 
formats. And so by explicitly specifying a mixed channelformats in the spec for 
the output file, or calling ImageBuf.set_write_format(), you should be able to 
coax ImageBuf.write() into writing at file with the correct mix of data 
formats, despite the fact that it's stored in memory as one type.

But I think the main place you are going wrong is in requesting uint8.

Unfortunately, it is a limitation of the OpenEXR format itself that the only 
pixel data types allowed are half, float, and uint32. If you ask for uint8, it 
cannot comply and it will choose a different, supported, data type for that 
file. It really has no choice but to promote those channels to 'half'.

Does that more or less set you on the right path?

        -- lg


> On Nov 13, 2019, at 3:56 PM, Jonathan Swartz <[email protected]> wrote:
> 
> Hi Larry et al,
> 
> I’ve just subscribed to the olio-dev list so apologies if this question has 
> been asked and answered before.
> 
> I’m using python (3.7 and OIIO 2.0.5) and trying to assemble a multichannel 
> ImageBuf which will contain RGB from one EXR source in float16 format and 
> some arbitrary uint8 channels read from some numpy.ndarray’s.  All these 
> channels will be written out to one EXR.  I could switch to C++ but I have 
> most of my code already in python so I thought I’d give the python bindings a 
> shot.  
> 
> I’m most of the way of there, the exr gets written to disk with the correct 
> channel names and so on, but all the channels whose format I expect to be 
> written as uint8 are written as float16.
> 
> From what I could gather from the python and C++ docs, my ImageBuf’s 
> ImageSpec.format would be used as the format for all channels unless 
> ImageSpec.channelformats is defined (and is a tuple of TypeDesc objects).
> 
> My code for assembling these channels and setting up the channel formats 
> looks something like the below.  The most relevant part is probably at the 
> end, I'm including my methodology for assembling the ImageBuf with the 
> various channels if that makes a difference. Any pointers on what I might be 
> doing incorrectly would be much appreciated
> 
> Cheers
> 
> Jonathan
> 
> 
> 
> import OpenImageIO as oiio
> exr_buf_input = olio.ImageBuf(“/path/to/my.exr”)
> exr_spec = exr_buf_input.spec()
> 
> # Setup output buffer for RGB + some arbitrary channels
> output_buf_spec = 
> oiio.ImageSpec(exr_spec.full_width,exr_spec.full_height,3,'half')
> channelnames = ['R', 'G', 'B'] + list_of_arb_channelnames
> output_buf_spec.channelnames = channelnames
> output_buf = oiio.ImageBuf(output_buf_spec)
> 
> # Copy just RGB channels out of my exr to my output buffer
> output_buf = oiio.ImageBufAlgo.channels(exr_buf_input,('R','G','B'))
> 
> # Create a buffer out of each numpy array[y][x], appending it to the output
> arb_buf_spec = 
> oiio.ImageSpec(exr_spec.full_width,exr_spec.full_height,1,oiio.TypeUInt8)
> channeltypes = [oiio.TypeHalf, oiio.TypeHalf, oiio.TypeHalf]
> for channel_array in arbitrary_channel_arrays:
>    temp_buf = oiio.ImageBuf(arb_buf_spec,False)
>    # assume channel_array's values are already normalized 0-255
>    temp_buf.set_pixels(oiio.ROI.All, channel_array.astype(np.uint8))
>    output_buf = oiio.ImageBufAlgo.channel_append(output_buf, temp_buf)
>    channeltypes.append(oiio.TypeUInt8)
> 
> # Set the ImageSpec's channelformats to the tuple of TypeDescs
> output_buf.specmod().channelformats = tuple(channeltypes)
> # The output buf's ImageSpec's channelformats are all the values I'd expect
> print(output_buf.spec().channelformats)
> # All the channels in the EXR float16
> output_buf.write('/tmp/output.exr')
> # All the channels in the EXR are still float16
> output_buf.write('/tmp/output.exr','uint8')
> _______________________________________________
> Oiio-dev mailing list
> [email protected]
> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org

--
Larry Gritz
[email protected]




_______________________________________________
Oiio-dev mailing list
[email protected]
http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org

Reply via email to