By the way, for those following along, if you're wondering how to make oiiotool 
take these very same shortcuts:

    oiiotool -i:ch=R,G,B:type=uint8:now=1 foo.exr ...


> On May 14, 2022, at 10:59 AM, Larry Gritz <l...@larrygritz.com> wrote:
> 
> I think that the problem here is that the ImageBuf will read in all the 
> channels, even though the get_pixels only copies out the 3 channels you need. 
> The I/O itself happens "lazily", triggered by the get_pixels call itself 
> needing pixel values, but at that point, it still doesn't know that you won't 
> subsequently try to access other channels in the ImageBuf, so the channel 
> restriction of get_pixels doesn't turn into a channel restriction for how the 
> file is read and stored.
> 
> Additionally, the ImageBuf will by default store the pixels in whatever the 
> "widest" data type of the file itself has (in the case of an OpenEXR, that 
> would mean half at best, and maybe float depending on what's in your file), 
> even though ultimately you only want UINT8 data in your program. (And if the 
> file is large, there's also probably yet another copy, or partial copy, in 
> the underlying ImageCache.)
> 
> But I think you can fix all of these issues by doing an explicit 
> ImageBuf::read() before the first time you access the pixels, using the 
> version of read() that lets you select the channel range and data type:
> 
>     buf.read(/*subimage*/ 0, /*miplevel*/ 0,
>              /*chbegin*/ 15, /*chend*/ 18,
>              /*forceread*/ true, /*convert*/ TypeDesc::UINT8);
>     // ... then ...
> 
>     // BEWARE! now channels 15... of the file are stored in 0... of the buf!
>     ROI roi(0, xres, 0, yres, 0, 1, /*chans:*/ 0, 4);
>     buf.get_pixels(roi, TypeDesc::UINT8, &pixels[0]);
> 
> Now the buf will internally store only 3 channels of UINT8.
> 
> See where I passed true for the "forceread" parameter? That forces it to read 
> the image right then, skipping use of the ImageCache and storing the entire 
> image in memory (well, the channels you asked for, I mean). So the ImageBuf 
> itself holds the channels you asked for, without an extra copy in the 
> ImageCache. The ImageCache is usually very helpful, especially if you only 
> need a small portion of a large image at any one time by one thread. The one 
> case where it's wasteful is if you need an entire image all at once, and it 
> can fit into memory so there is no benefit to reading it piece by piece only 
> as needed.
> 
> And given that we have the whole image loaded into the ImageBuf without any 
> ImageCache backing, it's possible that you can do one more better thing, 
> depending on how you use the data. With the forced read, the ImageBuf itself 
> holds channels 15,16,17 as UINT8, contiguously in memory starting at address 
> localpixels(). So do you really need the pixels to be copied (and stored 
> again) in your std::vector? Or can you directly use the ImageBuf's internal 
> storage of the pixels?
> 
> You can test if an ImageBuf's pixels are all in memory:
> 
>     if (buf.storage() == ImageBuf::LOCALBUFFER)
>         address = (const uint8*) buf.localpixels();
> 
> Actually, I think localpixels() will return nullptr if it doesn't use local 
> storage, so you don't need the separate check of storage(), but I still 
> wanted to point that out.
> 
> (I think everything I have written is true. Please double check it.)
> 
> 
>> On May 14, 2022, at 8:28 AM, ████刮 <15952002...@qq.com 
>> <mailto:15952002...@qq.com>> wrote:
>> 
>> Hello.
>> I'm trying to load OpenEXR sequence to memory then draw them with Opengl.
>> but these EXR files are so big with many sub-channels in(one file with 300M 
>> and more than 30 channels).
>>  i just want to load the "Beauty" pass.
>> 
>> here is what i was tried:
>> 
>>         ImageBuf buf = ImageBuf::ImageBuf(exr_filepath);
>>         const ImageSpec& spec = buf.spec();
>>         int xres = spec.width;
>>         int yres = spec.height;
>> 
>>         //   i just want to load the RGB data from the "Beauty" pass
>>         std::vector<UINT8> pixels(xres * yres * 3);
>> 
>>         //   for example the Beauty pass start with index of 15
>>         ROI roi(0, xres, 0, yres, 0, 1, /*chans:*/ 15, 18);
>>         buf.get_pixels(roi, TypeDesc::UINT8, &pixels[0]);
>> 
>> it works. but cost a huge amount of memory use with 
>> multi-threading(sometimes more than 80G) during loading all files.
>> here is my quesion:
>> like what i did. is this way to load all data together then save the "Beauty 
>> data" from them to the std::vector?
>> or just load the "Beauty" pass without cache all exr data first?
>> is this memory usage normal?
>> 
>> and i have checked the document. it looks like the ImageCache class is what 
>> i want. can i use this class in my situation?
>> is there anywhere i can find more example about this class?
>> 
>> thanks!
>> kong
>> 
>> _______________________________________________
>> Oiio-dev mailing list
>> Oiio-dev@lists.openimageio.org <mailto:Oiio-dev@lists.openimageio.org>
>> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org
> 
> --
> Larry Gritz
> l...@larrygritz.com <mailto:l...@larrygritz.com>
> 
> 
> 
> 
> 
> _______________________________________________
> Oiio-dev mailing list
> Oiio-dev@lists.openimageio.org
> http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org

--
Larry Gritz
l...@larrygritz.com





_______________________________________________
Oiio-dev mailing list
Oiio-dev@lists.openimageio.org
http://lists.openimageio.org/listinfo.cgi/oiio-dev-openimageio.org

Reply via email to