Reading/Writing Images to/from Memory (Rather than Files)

I’m trying to construct an itk::Image from an in-memory buffer, rather than from a file on disk. The image data itself is formatted as an NRRD. The buffer has been filled by an external program, and at some point I would like to be able to write back the image to this buffer (or allocate a new one and write it there).

itk::ImageFileReader only seems to support reading from a file, so that seems out.

itk::ImportImageFilter seems to deal with image data that has no corresponding metadata (or metadata that has been obtained from elsewhere). I could theoretically read through all of the metadata in the NRRD header, set it on the filter, and then import the actual data through that filter. I’m not 100% sure that would work, but either way, I would like to avoid re-implementing itk::NrrdImageIO.

I’ve spent a while looking around the internet for people trying to solve similar problems, and I am feeling a bit alone here. This poster had essentially the same problem, but got no responses. There is also this thread and the links that come off it (1, 2), where people talk quite optimistically about solving this. But it all links back to itk::FileFreeImageIO, which looks to me to be incomplete. I’m hoping I just don’t understand how it should be used. Could anyone give me a bit of direction?

Cheers,
Harold

1 Like

I now see that cannot be used to read arbitrary files from memory. It looks like it is mostly meant for testing. It gets metadata from “filename”. It “ignores” image pixels.

I guess the conclusion is: just write the file to disk and then read it normally. Modern OSes should cache that file in many situations, so the performance impact should not be big.

In 3D Slicer, we have a file-free ITK image IO plugin that we use to send/receive images in Slicer modules that are loaded as a dynamic library. You just register this plugin as any the other IO plugins. To pass an image to a module you don’t even need to write a file, just create a special filename (in our case it is slicer:<scene_memory_address>:<volume_node_id>) that the IO plugin recognizes and parses to get the memory address of the image. See source code of the IO plugin here and see how you specify an input volume here.

The advantage of this custom IO plugin technique that there is zero copy (not even in memory) and the reader does not need to know anything about this special IO plugin. It just gets a filename and asks ITK to read it and if it happens to be a shared memory address then it gets the image from there, otherwise the appropriate IO plugin will read the data from file.

There are a few disadvantages compared to simple file IO. There are a few more files to maintain and test (on all operating systems you support, at each major ITK update, etc.). There is also a disadvantage in running processing algorithms in the same process: 1. an error in the processing algorithm can crash the entire application; 2. it is not possible to force stopping a processing thread if that becomes non-responsive or takes too much resources (while it is easy to terminate a child process at any time).

This shared memory mechanism was essential 10-15 years ago. However, as @dzenanz noted above nowadays there is very little overhead in writing/reading files, so if you use a simple file format and no compression then the file IO time is typically negligible compared to the processing time.

1 Like