Main Content

Read Whole-slide Images with Custom Blocked Image Adapter

This example shows how to add support for reading whole-slide images by creating a custom blocked image adapter. The example creates a MATLAB interface to the OpenSlide C library, a C library that provides a simple interface to read whole-slide images (also known as virtual slides). The OpenSlide library is a product of the research group of M. Satyanarayanan at Carnegie Mellon University, School of Computer Science.

The example first builds a C++ interface to the OpenSlide library using the MATLAB clibgen function. The example then uses functions from the OpenSlide library to implement a custom blocked image adapter.

Make sure helper files are on the path.

addpath(pwd)

Create a MATLAB Interface for OpenSlide Library

This section uses the MATLAB clibgen.generateLibraryDefinition function to generate an interface to the OpenSlide library functions.

Download the OpenSlide Library and Add it to the Path

Download the latest OpenSlide library for your computer and operating system. This example assumes a Windows computer.

Create a variable that points to where you extracted the OpenSlide Library. This folder is expected to contain bin\, include\, and lib\ subfolders.

OpenSlideInstall = 'I:\my_example\openslide-win64-20171122';
dir(OpenSlideInstall)
.             README.txt    bin           lib           
..            VERSIONS.txt  include       licenses      

Add the location of the OpenSlide shared library to the system path.

sharedLibLoc = fullfile(OpenSlideInstall, 'bin');
systemPath = getenv('PATH');
setenv('PATH', [sharedLibLoc ';' systemPath])

Set Up Your Development Environment

Create variables that contain the names of folders containing key elements of your development environment.

Create a variable that points to the folder where you want to store the predefined definition file for the OpenSlide interface that you are creating.

ExampleDir = 'I:\my_example';

Create a variable to point to a test image file. Download CMU-1.zip test file from the OpenSlide test data page, and update the variable below to point to the extracted image file.

imageLocation = 'I:\my_example\CMU-1.mrxs';

Generate an OpenSlide Interface Definition File

Generate a library interface definition file using the clibgen.generateLibraryDefinition function.

Create a variable that points to a writable folder to store the generated interface files. Create a folder in which to write the MATLAB OpenSlide Interface file and change to that folder.

OpenSlideInterface = 'I:\my_example\interfaceFolder';

if ~isfolder(OpenSlideInterface)
    mkdir(OpenSlideInterface)
end
cd(OpenSlideInterface)

Create variables to point to the OpenSlide library folder, the two OpenSlide header files, the path to the header files, the name of the OpenSlide library, and define the name you want to assign to the generated interface.

libPath = fullfile(OpenSlideInstall,'lib');
hppFiles = {'openslide.h', 'openslide-features.h'};
hppPath = fullfile(OpenSlideInstall, 'include', 'openslide');
libFile = 'libopenslide.lib';
myPkg = 'OpenSlideInterface';

Call the clib.generateLibraryDefinition function, specifying the variables you have set up.

  • Header file names (hppFiles) and location (hppPath)

  • Folder containing include files (hppPath)

  • Shared library name (libFile) and location (libPath)

  • Name to give to the generated interface library (myPkg) -- Optional

You can optional set the 'Verbose' parameter to true to display messages produced during generation.

% Clear previous run (if any)
if isfile('defineOpenSlideInterface.m')
    delete('defineOpenSlideInterface.m')
end
clibgen.generateLibraryDefinition(fullfile(hppPath,hppFiles),...
      'IncludePath', hppPath,...
      'Libraries', fullfile(libPath,libFile),...
      'PackageName', myPkg,...
      'Verbose',false)
Using MinGW64 Compiler (C++) compiler.
Generated definition file defineOpenSlideInterface.mlx and data file 'OpenSlideInterfaceData.xml' contain definitions for 24 constructs supported by MATLAB.
21 construct(s) require(s) additional definition. To include these construct(s) in the interface, edit the definitions in defineOpenSlideInterface.mlx.
Build using build(defineOpenSlideInterface).
Use the 'Verbose' option to see the warnings generated while parsing the files for generating interface.

Edit the Generated Interface Definition File

The clibgen.generateLibraryDefinition command creates two files: the library interface definition file defineOpenSlideInterface.m and defineOpenSlideInterface.mlx. To use the generated interface file to create a blocked image adapter, certain edits are required. The toolbox provides a template interface file that contains these edits but you still need to provide location information for certain key folders. This section performs these edits on the template file.

First, rename the interface file you generated with the clib.generateLibraryDefinition command and keep it as a backup file.

movefile('defineOpenSlideInterface.m','defineOpenSlideInterface_generated.m');

Delete the .mlx file created by the clibgen.generateLibraryDefinition function and then call rehash.

delete defineOpenSlideInterface.mlx;
rehash

Edit the interface definition file template file that is included with the toolbox. The edits provide the locations of key folders in your installation. First, open the interface definition template file, included with this example, for read access. Read the contents into a variable, called interfaceContents, and then close the template file.

fid = fopen(fullfile('defineOpenSlideInterface_template.m'),'rt');
interfaceContents = fread(fid, 'char=>char');
fclose(fid);

Update place holder variables in the template file variable, interfaceContents, with your actual folder names.

interfaceContents = strrep(interfaceContents', 'OPENSLIDE_INSTALL_LOCATION', OpenSlideInstall);
interfaceContents = strrep(interfaceContents, 'OPENSLIDE_INTERFACE_LOCATION', OpenSlideInterface);

Now, write the updated interface definition template variable to a new file. Open an interface definition file for write access, write the template file variable to the file, and then close the file..

fid = fopen('defineOpenSlideInterface.m','wt');
fwrite(fid, interfaceContents);
fclose(fid);

To verify that the changes to the interface file were successful, you can view the differences between the generated interface file and the edited interface template file.

Create the Library Interface

Using the OpenSlide interface definition file, use the build command to create a MATLAB OpenSlideInterface shared library.

build(defineOpenSlideInterface)
Building interface file 'OpenSlideInterfaceInterface.dll'.
Interface file 'OpenSlideInterfaceInterface.dll' built in folder 'I:\my_example\interfaceFolder\osInterface\OpenSlideInterface'.
To use the library, add the interface file folder to the MATLAB path.

Add the path of the library to the generated interface library.

addpath osInterface\OpenSlideInterface\

Be sure to click the link in the message after the build is complete to add the interface file to the path

To view the functional capabilities of the interface library, use the summary function.

summary(defineOpenSlideInterface)
MATLAB Interface to OpenSlideInterface Library

Class clib.OpenSlideInterface.openslide_t

  No Constructors defined

  No Methods defined

  No Properties defined

Functions
clib.OpenSlideInterface.openslide_t clib.OpenSlideInterface.openslide_open(string)
int32 clib.OpenSlideInterface.openslide_get_level_count(clib.OpenSlideInterface.openslide_t)
[int64,int64] clib.OpenSlideInterface.openslide_get_level_dimensions(clib.OpenSlideInterface.openslide_t,int32,int64,int64)
    Note: 'int64' used as MLTYPE for C++ pointer argument.
    Passing nullptr is not supported with 'int64' types.
    To allow nullptr as an input, set MLTYPE to clib.array.
double clib.OpenSlideInterface.openslide_get_level_downsample(clib.OpenSlideInterface.openslide_t,int32)
clib.OpenSlideInterface.openslide_read_region(clib.OpenSlideInterface.openslide_t,clib.array.OpenSlideInterface.UnsignedInt,int64,int64,int32)
clib.OpenSlideInterface.openslide_close(clib.OpenSlideInterface.openslide_t)

Test the Library Interface

To test the library interface, try using the functions in the library with the sample image.

Load the sample image file using the openslide_open function.

ob = clib.OpenSlideInterface.openslide_open(imageLocation);

Get the number of levels of slides present in this example file.

levels = clib.OpenSlideInterface.openslide_get_level_count(ob);

Get the dimensions of the slide in level 0.

[w, h] = clib.OpenSlideInterface.openslide_get_level_dimensions(ob,int32(0),int64(0),int64(0));
disp([w, h])
   109240   220696

Read a region from level 0 using the openslide_read_region function. Setup a clibArray of type UnsignedInt with desired width and height dimensions. Specify the top left x-coordinate and the top left y-coordinate in the level 0 reference frame.

rawCData = clibArray('clib.OpenSlideInterface.UnsignedInt', [1024, 1024]);
clib.OpenSlideInterface.openslide_read_region(ob,rawCData,int64(33792),int64(113664),int32(0));

Post-process the acquired region from the clibArray to convert it into a uint8 RGB image.

rawImageData = uint32(rawCData);
RGBA = typecast(rawImageData(:), 'uint8');
% Ignore the A channel
RGB(:,:,1) = reshape(RGBA(3:4:end),1024,1024);
RGB(:,:,2) = reshape(RGBA(2:4:end),1024,1024);
RGB(:,:,3) = reshape(RGBA(1:4:end),1024,1024);

Display the processed image region.

figure;
imshow(RGB);

Create Blocked Image Custom Adapter for Reading Whole-Slide Images

To read whole-slide images, create a custom Adapter for block-based reading and writing that uses the capabilities of the OpenSlide Interface built above.

Subclass the images.blocked.Adapter Class

To create a blocked image adapter, first create a class that subclasses the blocked image adapter interface class, images.blocked.Adapter. To learn more about blocked images and creating a blocked image adapter, view the images.blocked.Adapter documentation.

Create a read-only OpenSlide adapter by implementing the following methods:

  • openToRead - open source for reading

  • getInfo - gather information about source

  • getIOBlock - get specified IO block

Use the OpenSlide interface functions generated above to implement these methods.

A sample adapter is included in this example, OpenSlideAdapter.m. To view this adapter, you can open the file in an editor.

Use the new adapter with the sample image by specifying it in the blockedImage object constructor:

bim = blockedImage(imageLocation, "Adapter", OpenSlideAdapter)
bim = 
  blockedImage with properties:

   Read only properties
             Source: "I:\my_example\CMU-1.mrxs"
            Adapter: [1×1 OpenSlideAdapter]
               Size: [10×3 double]
       SizeInBlocks: [10×3 double]
    ClassUnderlying: [10×1 string]

   Settable properties
          BlockSize: [10×3 double]
           UserData: [1×1 struct]

disp(bim.Size)
      220696      109240           3
      110348       54620           3
       55174       27310           3
       27587       13655           3
       13793        6827           3
        6896        3413           3
        3448        1706           3
        1724         853           3
         862         426           3
         431         213           3
bigimageshow(bim)

See Also

|