OK, that sounds reasonable. So we have: * If you ask for a specific type, convert and return an array of that type. If you ask for HALF, the half bit pattern gets returned in a uint16 array, since there is no true half type.
* If you ask for UNKNOWN (explicitly "give me raw data"), it returns an array of unsigned chars containing the raw data. Everybody can live with that? > On Feb 19, 2016, at 8:08 AM, Haarm-Pieter Duiker <[email protected]> > wrote: > > Of the options "pass half values disguised as an unsigned short array" feels > the cleanest to me. You keep the right number of components in the array, if > you have any checks for that, and the data to be convert to halfs is already > grouped appropriately. > > Converting to halfs is also a one line call to numpy: > np.frombuffer(np.getbuffer(np.uint16(uint16Value)), dtype=np.float16) > Ex. https://github.com/hpd/CLF/blob/master/python/aces/clf/Common.py#L92 > <https://github.com/hpd/CLF/blob/master/python/aces/clf/Common.py#L92> > > HP > > > > > > On Thu, Feb 18, 2016 at 4:06 PM, Larry Gritz <[email protected] > <mailto:[email protected]>> wrote: > In C++, asking for UNKNOWN just copies the native format data and leaves it > for you to sort out. But to C++, a buffer is a buffer, you're passing it a > void* in any case. > > In Python, it's dynamic typing, so read_image RETURNS an array, and it has to > be an array of some type. Which type? > > I think we all are coming to agree that if you ask for UNKNOWN, probably the > most analogous thing (to C++) is to return an unsigned char array, filled > with the raw data, and leave you to sort it out. That's as close to "untyped > raw buffer" as we can get. > > If you *ask* for HALF, it's nonsensical, because you can't make an actual > half array in Python. You could promote and convert it to float. Or you could > return raw values in unsigned char array (like if you'd passed UNKNOWN). Or, > yeah, another possibility is to pass half values disguised as an unsigned > short array? > > I'm not super fond of the last choice. > > Right now, we do something stupider than any of those -- which is to pack raw > half values into a buffer, but the buffer advertises itself as being a float > array. That clearly needs to change. It was never intentional; I just never > thought carefully about that case because I never imagined anybody asking for > a type that didn't exist in Python. > > So, current proposal on the table: > > * If you ask for a type that can be a valid Python array type, convert and > return an array of that type. > > * If you ask for UNKNOWN (explicitly "give me raw data") or HALF (implicitly > so, because it doesn't exist in Python), it returns an array of unsigned > chars containing the raw data. > > > >> On Feb 18, 2016, at 3:36 PM, Haarm-Pieter Duiker <[email protected] >> <mailto:[email protected]>> wrote: >> >> Returning a series of unsigned 16 bit ints for a call with the type half >> feels like a nice middle ground. The consumer will have to know that halfs >> aren't natively supported in Python, and how to convert from unsigned short >> to half, but that doesn't feel like a large burden. >> >> I can't speak to the expected behavior of the UNKNOWN in Python. I haven't >> used that path in Python or C++. >> >> HP >> >> >> >> >> >> >> >> >> On Thu, Feb 18, 2016 at 1:23 PM, Larry Gritz <[email protected] >> <mailto:[email protected]>> wrote: >> I don't have especially strong feelings about this one way or the other. >> >> Just returning a raw data byte array matches the C++ behavior more closely, >> no argument there. >> >> On the "con" side, perhaps I was thinking of compatibility? We're really >> talking about changing the meaning of oiio.UNKNOWN from "use spec.format" to >> "return raw data", which differ in the case of mixed channel types. >> >> Are there Python programs out there that pass UNKNOWN (or pass nothing, >> defaulting to UNKNOWN) and rely on getting the right kind of array back that >> matches spec.format? >> >> >> >> >>> On Feb 18, 2016, at 12:58 PM, Andrew Gartner <[email protected] >>> <mailto:[email protected]>> wrote: >>> >>> "Second, I could collapse 2a and 2b, and just say that if you ask for >>> UNKNOWN, you get an array of uint8 back with the native raw data" >>> >>> Just out of curiosity, what are the drawbacks to doing this? I admit I like >>> having some way of getting at the raw data at any time (hence my original >>> method of exposing the native calls). That allowed me to check my imagespec >>> and regardless of whether I had a mixed format image or all half data I >>> could get everything in one read call. Granted I'm used to keeping track of >>> and manipulating the strides of those arrays in bytes just out of old habit >>> (and C++ usage) so maybe I'm the minority opinion. >>> >>> Even so, your current thinking still works if that's where the consensus is >>> I'm happy to use it as such. >>> >>> Thanks again >>> >>> ~Andrew >>> >>> On Thu, Feb 18, 2016 at 12:21 PM, Larry Gritz <[email protected] >>> <mailto:[email protected]>> wrote: >>> I think that the only format that we can encounter as pixel data, which >>> does not exist in Python arrays, is 'half'. >>> >>> So let me rephrase my current thinking: >>> >>> 1. If you ask for a specific type (except HALF), you'll get a Python array >>> of that type holding the converted values. >>> >>> 2. Otherwise (i.e., you ask for UNKNOWN or HALF), you will get the native >>> (raw) data. >>> (a) If all channels are the same data type and it's anything but half, >>> you'll get the data as a Python array of that type. >>> (b) Otherwise (half, or mixed channel types), you'll get the data as a >>> Python array of unsigned bytes. >>> >>> Note that (1) is the easy case to deal with: ask for the type you want, let >>> it do the conversion. If you go for option (2) by asking for native data, >>> you get a blob and it's up to you to figure out what to do with it. >>> >>> There are two other choices we could make. I'm not inclined to at the >>> moment, but would be happy to do so if people think it's helpful. First, if >>> you ask for HALF, I could have it return float. Second, I could collapse 2a >>> and 2b, and just say that if you ask for UNKNOWN, you get an array of uint8 >>> back with the native raw data, even if it happened to be all channels of >>> the same type, a type that you could have made into a Python array of the >>> right type. >>> >>> >>>> On Feb 17, 2016, at 11:16 PM, Haarm-Pieter Duiker <[email protected] >>>> <mailto:[email protected]>> wrote: >>>> >>>> Picking this up a little later in the day. Sorry about that. Adding quotes >>>> from earlier in the thread just so it's clear what I'm responding to. >>>> >>>> The current status: >>>> " >>>> If you read_image(oiio.FLOAT) of a half image (on disk), you get floats >>>> back? >>>> " >>>> Yes. >>>> >>>> " >>>> But if you read_image(oiio.HALF) of a half image, you get what appears to >>>> be an array of floats, but they are actually packed half values? >>>> " >>>> Yes. >>>> >>>> The proposal: >>>> " >>>> 1. If you ask for a (non-UNKNOWN) format that exists in Python, it >>>> converts to and returns an array of that format. >>>> " >>>> This is the current behavior, no? >>>> >>>> " >>>> 2. If you ask for UNKNOWN, or a format that doesn't exist, it returns the >>>> raw data in an unsigned char array. >>>> " >>>> It feels like this is two proposals (Trying not to clash with your earlier >>>> 2a and 2b): >>>> 2c. If you ask for UNKNOWN, return raw data in an unsigned char array >>>> 2d. If you ask for a format that doesn't exist, return raw data in an >>>> unsigned char array >>>> >>>> 2c. feels right. It should work for the case of typical RGB or RGBA images >>>> but also for multi-layer EXRs. The consumer can convert the channels to >>>> their intended types using methods from the ImageSpec. I'd suggest that >>>> asking for UNKNOWN lead unequivocally to a raw unsigned char array. >>>> Supporting the special cases described in the 2a and 2b listed earlier >>>> would require additional logic on the consuming code side to account for >>>> those cases. Feels like a recipe for lots of brittle special case logic. >>>> >>>> 2d. is less clear. How is the change in behavior from returning real >>>> values for known types to returning raw char array data for unknown types >>>> signaled to the consumer? Is this still something that programmers have to >>>> just know a priori? How is this different from the current behavior? >>>> >>>> I suppose the list of types known to OIIO but not Python is finite and >>>> likely to shrink over time. Having special cases like we have in that >>>> example code, isn't such a big deal in the mean time, but then that's just >>>> saying the the current behavior is fine. >>>> >>>> Hope that's helpful in some way. Aside from agreeing that adding an >>>> UNKNOWN option is a good idea, we're still left without a good way to >>>> consume half data without accounting for it explicitly. >>>> >>>> HP >>>> >>>> >>>> >>>> >>>> >>>> >>>> >>>> >>>> >>>> >>>> >>>> >>>> >>>> On Wed, Feb 17, 2016 at 4:35 PM, Andrew Gartner <[email protected] >>>> <mailto:[email protected]>> wrote: >>>> That would certainly take care of things for me. Hopefully not too much of >>>> an impact on others as well. >>>> >>>> ~Andrew >>>> >>>> >>>> >>>> On Wed, Feb 17, 2016 at 4:20 PM, Larry Gritz <[email protected] >>>> <mailto:[email protected]>> wrote: >>>> So I'm proposing: >>>> >>>> 1. If you ask for a (non-UNKNOWN) format that exists in Python, it >>>> converts to and returns an array of that format. >>>> >>>> 2. If you ask for UNKNOWN, or a format that doesn't exist, it returns the >>>> raw data in an unsigned char array. >>>> >>>> >>>> There is a variation: >>>> >>>> 2a. If you ask for UNKNOWN, and all channels are the same format and it's >>>> a type that exists in Python, return that type. >>>> 2b. If you ask for UNKNOWN and it's a "mixed type" file, or a single type >>>> but one that doesn't exist in Python, or the type you ask for doesn't >>>> exist in Python, return raw data packed into an unsigned char array. >>>> >>>> >>>> >>>>> On Feb 17, 2016, at 4:10 PM, Andrew Gartner <[email protected] >>>>> <mailto:[email protected]>> wrote: >>>>> >>>>> Yea the C++ implementation works well with oiio.UNKNOWN, I kinda miss >>>>> that in the python side to be honest. Right now it looks like things >>>>> revert back to spec.format if oiio.UNKNOWN is supplied to read_scanlines, >>>>> that can be problematic if you have multiple formats in a single image so >>>>> I've avoided it. >>>>> >>>>> @Larry, to you question about returning an unsigned char array, I like >>>>> the idea on principle in that it preserves the decoupling as you said. >>>>> I'm wondering if there would be any weirdness if you had to grab multiple >>>>> channels of an image that had different data types one of which isn't >>>>> representable in python? Would it default to just unsigned char yet again >>>>> in that case? >>>>> >>>>> @Haarm: interesting, I didn't realize they were concatenated/packed like >>>>> that! I just saw the 'f' in the python array and assumed I was seeing >>>>> promoted values :) I'm still scratching my head over the multiple format >>>>> reads though, same as for Larry's idea. >>>>> >>>>> Thanks for the replies, Cheers, >>>>> >>>>> ~Andrew >>>>> >>>>> >>>>> >>>>> On Wed, Feb 17, 2016 at 3:49 PM, Haarm-Pieter Duiker >>>>> <[email protected] <mailto:[email protected]>> wrote: >>>>> If you're up for using numpy, this will get you the half float values >>>>> without too much extra work: >>>>> oiioFloats = inputImage.read_image(oiio.HALF) >>>>> oiioHalfs = np.frombuffer(np.getbuffer(np.float32(oiioFloats)), >>>>> dtype=np.float16) >>>>> >>>>> One note, the current OIIO Python implementation doesn't promote the >>>>> halfs to float on read. The 'float' values in the returned buffer are >>>>> actually each two concatenated half values, and the float buffer will >>>>> have half as many entries as you would expect. >>>>> >>>>> Example usage for reading here: >>>>> https://github.com/hpd/CLF/blob/master/python/aces/filterImageWithCLF.py#L126 >>>>> >>>>> <https://github.com/hpd/CLF/blob/master/python/aces/filterImageWithCLF.py#L126> >>>>> and the reverse for writing: >>>>> https://github.com/hpd/CLF/blob/master/python/aces/filterImageWithCLF.py#L193 >>>>> >>>>> <https://github.com/hpd/CLF/blob/master/python/aces/filterImageWithCLF.py#L193> >>>>> >>>>> HP >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> On Wed, Feb 17, 2016 at 3:25 PM, Larry Gritz <[email protected] >>>>> <mailto:[email protected]>> wrote: >>>>> In C++, you can just call read_scanlines and pass format=UNKNOWN to get >>>>> back the raw data in its original format. >>>>> >>>>> The problem is that in Python, there is no 'half' so it's not quite sure >>>>> what to return. >>>>> >>>>> I kinda like the decoupling of the raw reads (read_native_*) which are >>>>> the part overloaded by the individual format readers, from the >>>>> app-callable read_*. So perhaps rather than exposing read_native_*, we >>>>> should just modify the Python bindings for read_* to notice that if the >>>>> native raw data is not a type representable in Python, to return it as an >>>>> unsigned character array? >>>>> >>>>> >>>>> > On Feb 17, 2016, at 2:55 PM, Andrew Gartner <[email protected] >>>>> > <mailto:[email protected]>> wrote: >>>>> > >>>>> > Hey all, >>>>> > >>>>> > Apologies if this has come up before, but I'm curious if anyone had >>>>> > considered exposing ImageInput.read_native_scanlines() on the python >>>>> > side before. The reason I ask is mainly because the half datatype >>>>> > doesn't exist in the native python array class which OIIO uses for >>>>> > python reads. Currently the python array will punt and for anything to >>>>> > float (which I'd rather avoid). >>>>> > >>>>> > I had put together an implementation in OIIO 1.5 that simply took the >>>>> > pixel size as a parameter and exposed read_native_scanlines that way >>>>> > and that allowed me to get the right data properly into either numpy or >>>>> > a raw char python array. However, I'd rather not be forked off like >>>>> > that as it's a headache trying to remain current with the mainline, >>>>> > plus others may find it useful. >>>>> > >>>>> > Does anyone think exposing the function in general makes sense? I'm >>>>> > happy to send the implementation if anyone cares to see it as well. >>>>> > >>>>> > Cheers, >>>>> > >>>>> > ~Andrew >>>>> > >>>>> >>>>> -- >>>>> Larry Gritz >>>>> [email protected] <mailto:[email protected]> >>>>> >>>>> >>>>> _______________________________________________ >>>>> Oiio-dev mailing list >>>>> [email protected] <mailto:[email protected]> >>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>>>> >>>>> >>>>> _______________________________________________ >>>>> Oiio-dev mailing list >>>>> [email protected] <mailto:[email protected]> >>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>>>> >>>>> >>>>> _______________________________________________ >>>>> Oiio-dev mailing list >>>>> [email protected] <mailto:[email protected]> >>>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>>> >>>> -- >>>> Larry Gritz >>>> [email protected] <mailto:[email protected]> >>>> >>>> >>>> >>>> _______________________________________________ >>>> Oiio-dev mailing list >>>> [email protected] <mailto:[email protected]> >>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>>> >>>> >>>> >>>> _______________________________________________ >>>> Oiio-dev mailing list >>>> [email protected] <mailto:[email protected]> >>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>>> >>>> >>>> _______________________________________________ >>>> Oiio-dev mailing list >>>> [email protected] <mailto:[email protected]> >>>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>> >>> -- >>> Larry Gritz >>> [email protected] <mailto:[email protected]> >>> >>> >>> >>> _______________________________________________ >>> Oiio-dev mailing list >>> [email protected] <mailto:[email protected]> >>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >>> >>> >>> _______________________________________________ >>> Oiio-dev mailing list >>> [email protected] <mailto:[email protected]> >>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >>> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >> >> -- >> Larry Gritz >> [email protected] <mailto:[email protected]> >> >> >> >> _______________________________________________ >> Oiio-dev mailing list >> [email protected] <mailto:[email protected]> >> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> >> >> >> _______________________________________________ >> Oiio-dev mailing list >> [email protected] <mailto:[email protected]> >> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org >> <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> > > -- > Larry Gritz > [email protected] <mailto:[email protected]> > > > > _______________________________________________ > Oiio-dev mailing list > [email protected] <mailto:[email protected]> > http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org > <http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org> > > > _______________________________________________ > 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
