The problem was the implementation of handling the case where you pass chend < 
chbegin, which is supposed to mean "all channels."

Proposed fix here:  https://github.com/OpenImageIO/oiio/pull/2742 
<https://github.com/OpenImageIO/oiio/pull/2742>

As a workaround, rather than call add_tile() and get_tile() with chbegin=1, 
chend=0, I would recommend passing chbegin=0 and chend=the correct number of 
channels.

In addition to working around this bug, I think it's better practice. In code 
like this, passing the special signal for "all channels" but just assuming what 
that is, seems dangerous. For example, you are taking it for granted that your 
files have the same resolution and number of channels in each of the subimages, 
but that doesn't need to be the case, and code that relies on that assumption 
will sooner or later exhibit tricky bugs when you encounter a file for which 
(by design or accident) the assumptions are false.


Now then, TOTALLY UNRELATED TO THIS BUG, I have a few comments regarding things 
I noticed about your code snippet that as a user of OIIO you may find helpful 
to keep in mind:

>     auto test_file = [](const ustring& filename){

There is never a reason to have a `const ustring&`. A ustring is 64 bits wide 
(same as the pointer that underlies a reference), and passing it by value does 
not do a deep copy (nor does it change ownership or even diddle reference 
counts). It just adds a needless doubly indirect access.


> auto tile = ic->get_tile(filename, ss, 0, 0, 0, 0, 1, 0);

Your uses of get_tile (which increases a reference count on the tile so that 
it's not freed while still potentially in use) don't have corresponding calls 
to release_tile(), so the cache will think those tiles are never safe to 
reclaim, and eventually the cache will fill up.


>     int number_of_subimages = 0;
>     while (ic->get_imagespec (filename, spec, number_of_subimages)){
>         number_of_subimages++;
>     }


Repeatedly calling get_imagespec until it fails is a fairly inefficient way to 
determine the number of subimages (you end up needlessly copying the spec of 
each subimage). You could instead simply query it directly:

    int nsubimages = 0;
    ic->get_image_info(filename, 0, 0, ustring("subimages"), OIIO::TypeInt, 
&nsubimages);

Also, it is worth noting that the `while` loop that you wrote will end up with 
`spec` containing the ImageSpec of the *last* subimage in the file. It may be 
fine for this example file, but in general I don't think it's safe to assume 
that all subimages will have matching resolutions, numbers of channels, or 
anything else where in this example you assume that whatever spec.* holds is 
valid for all the subimages.

In fact, what I find is that for many real-world multi-image files, quite often 
the useful metadata like DateTime is diligently set for the FIRST subimage 
only, and omitted from the subsequent ones. So if you're going to assume that 
one subimage is representative of the whole stack, it's probably safer to use 
subimage 0 (rather than nsubimages-1) as the template.

Hope this helps,

        -- lg


> On Oct 11, 2020, at 9:12 PM, Arman Garakani <arman.garak...@darisa.net> wrote:
> 
> I am adding unit test as part of adding OpenImageIO to our app ( Machine 
> Learning / Computer Vision / Biological Assays ). Before going further, oiio 
> solves a fundamental problem in developing media accessing functionality. I 
> have a very directed functionality for videos. Oiio has more functionality, 
> simpler API and supports much wider image format APIs. 
> 
> Here is the problem I am having with small tif stack files I use for testing. 
> <zser16.tif><zser8.tif>
> 
> 
> Here is what iinfo says about it:
> 
> $ iinfo zser8.tif 
> zser8.tif :  160 x  128, 1 channel, uint8 tiff (11 subimages)
> 
> OpenImageIO ImageCache statistics (shared) ver 2.1.18
>   Options:  max_memory_MB=2048.0 max_open_files=100 autotile=0
>             autoscanline=0 automip=0 forcefloat=0 accept_untiled=1
>             accept_unmipped=1 deduplicate=1 unassociatedalpha=0
>             failure_retries=0 
> 
> In the function below, the output before the loop calling add_tile, outputs:
> 11 (160,128) 255::-1::-1::NA::8
> 
> 
> call to add_tile generates a memory access fault. The interesting thing here 
> is that similar file but containing 16bit data works fine. 
> 
> 
> 
> 
>  This is a simple test I am developing to assess hit and miss performance 
> with ImageCache. The test function is a lambda here for simplicity. 
> 
> 
> 
> 
> 
> TEST(oiio, basic){
>     
>     auto test_file = [](const ustring& filename){
>         // Create a private ImageCache so we can customize its cache size
>         // and instruct it store everything internally as floats.
>     ImageCache* ic = ImageCache::create(true);
>     ic->attribute("autotile", 0);
>     ic->attribute("max_memory_MB", 2048.0);
> 
>     
>     ImageSpec spec;
>     int number_of_subimages = 0;
>     while (ic->get_imagespec (filename, spec, number_of_subimages)){
>         number_of_subimages++;
>     }
>     unsigned int maxval = (unsigned int)get_intsample_maxval(spec);
>     int xres = spec.width;
>     int yres = spec.height;
>     int channels = spec.nchannels;
>     int i = spec.get_int_attribute ("oiio:subimages", -1.0);
>     int bp = spec.get_int_attribute ("oiio:BitsPerSample", -1);
>     float fps = spec.get_float_attribute ("Fps", -1.0f);
>     std::string s = spec.get_string_attribute ("DateTime", "NA");
>     
>     std::vector<unsigned char> pixels (xres*yres*channels);
>     std::cout << number_of_subimages << " (" << xres << "," << yres << ") " <<
>         maxval << "::" << i << "::" <<  fps << "::" << s << "::" << bp << 
> std::endl;
> 
>     for (int ss = 0; ss < number_of_subimages; ss++){
>         if (ss & 1)
>             ic->add_tile(filename, ss, 0, 0, 0, 0, 1, 0, TypeDesc::UINT8, 
> pixels.data());
>     }
>     
>     {
>     std::cout << " Half Cached " << std::endl;
>             // average hit time and miss time
>         float hits(0.0), miss(0.0);
>         int hitn(0), missn(0);
>         for (int ss = 0; ss < number_of_subimages; ss++){
>             if (ss & 1){
>                 OIIO::Timer hitimer;
>                 auto tile = ic->get_tile(filename, ss, 0, 0, 0, 0, 1, 0);
>                 assert(tile != nullptr);
>                 hits += hitimer();
>                 hitn++;
>             }
>             else{
>                 OIIO::Timer misstimer;
>                 ic->add_tile(filename, ss, 0, 0, 0, 0, 1, 0, TypeDesc::UINT8, 
> pixels.data());
>                 miss += misstimer();
>                 missn++;
>             }
>         }
>         hits /= hitn;
>         miss /= missn;
>         std::cout << hitn << "," << missn << std::endl;
>         
>         std::cout << hits * 1000 << " , " << miss * 1000 << std::endl;
>     }
>     
>     std::cout << " All Cached " << std::endl;
>     
>     float hits(0.0), miss(0.0);
>     int hitn(0), missn(0);
>     for (int ss = 0; ss < number_of_subimages; ss++){
>         OIIO::Timer hitimer;
>         auto tile = ic->get_tile(filename, ss, 0, 0, 0, 0, 1, 0);
>         if (tile != nullptr){
>             hits += hitimer();
>             hitn++;
>         }
>         else{
>             miss += hitimer();
>             missn++;
>         }
>     }
>     hits /= hitn;
>     if (missn) miss /= missn;
>     std::cout << hitn << "," << missn << std::endl;
>     std::cout << hits * 1000 << " , " << miss * 1000 << std::endl;
>     std::cout << ic->getstats() << std::endl;
>         
>     };
>     
>     
>     auto res = dgenv_ptr->asset_path("zser8.tif");
>     EXPECT_TRUE(res.second);
>     EXPECT_TRUE(boost::filesystem::exists(res.first));
>     ustring filename (res.first.c_str());
>     test_file(filename);
>     
> }
> 
> 
> _______________________________________________
> 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