Cris’ Image Analysis Blog

theory, methods, algorithms, applications

DIPimage 2.6 released

Today we released version 2.6 of DIPimage and DIPlib. The change list is rather short. There are two items that I think are important: 1) We fixed a bug that caused an unnecessary copy of the output image(s) in the DIPlib-MEX interface, slowing down functions especially for large images. 2) We introduced a new setting to automatically make use of a feature introduced in the previous release.

The bug

Thanks to some attentive users, and some nifty sleuthing by a colleague, we were able to track down a curious bug: it seems that, when the DIPlib-MEX interface created a dip_image object, the data array inside the object would be copied while exiting the MEX-file. I am very sure that this did not happen when we first developed the interface (way back in 1999, when the newest MATLAB version was 5.3!). I don’t know when this “new behaviour” was introduced, but it certainly wasn’t announced in the release notes. We now avoid the copy by creating an empty object, and then inserting the data array into it.

For simple functions working on large images, the impact of this bug was huge. For example, a simple arithmetic operation on a large image is completely limited by the speed at which memory can be accessed. Computing the division with a constant takes just as much time as making a copy of the data. Let’s test this:

a = repmat(readim,[6,7,20]);
timeit(@()(a/2))
ans =
    1.3306

I created a large image by replicating a standard image; the size of a is 1536×1792×20 = 55 Mpixels, of type uint8. Then I time the division of this image by 2. This produces a single-precision floating-point (sfloat) image. The computation time was 1.33 s with DIPimage 2.5.1. Let’s restart MATLAB with the new version of DIPimage, and repeat the experiment:

a = repmat(readim,[6,7,20]);
timeit(@()(a/2))
ans =
    0.6345

As expected, the computation time is about half. For more complex functions, the difference might not be as dramatic, but it certainly is worth upgrading!

A new setting

In the previous version of DIPimage we introduced the ability to do arithmetic operations and specify the data type of the output image . By default, DIPimage usually chooses sfloat as the output data type. This is to avoid unexpected results, as keeping the data type of the image typically leads to rounding errors or overflow, which can simply be avoided by choosing a floating-point data type. Note that this default behaviour is usually what is expected, and frees the user from having to think about what data type to use.

However, sometimes advanced users want to control the output data type. For example, when working with very large images, it can be convenient (saves time, avoids memory problems) to use only uint8 or uint16 data types (a sfloat image takes up 4 times as much space as a uint8 image). In the previous version of DIPimage, one could then type, for example, dip_arith(a,2,'div','uint8') instead of a/2. Not very elegant, not very readable, but hey! it saves up memory space!

With the new version of DIPimage comes a new setting, called 'KeepDataType'. It causes the output of arithmetic operations to be the same as that of the input images. If the types are different, then the larger of the two types is chosen, except if one of the inputs is a MATLAB array, as we only look at the data type of the image. This simplifies the use of the memory-saving feature, as the choice made is usually a good choice. However, note that overflow and rounding errors can (and will) occur! Let’s try the same division as before, but using the new setting:

dipsetpref KeepDataType on
a = readim;
a = repmat(a,[6,7,20]);
timeit(@()(a/2))
ans =
    0.3595

As you can see, since the output image is only a fourth the size it was before, it takes a lot less time to write the output to memory. But again, be careful when using this feature! You will get unexpected output if you’re not careful!