Read Whole-Slide Images with OpenSlide
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 OpenSlide library from the OpenSlide GitHub® repository. This example assumes a Windows® computer, but the repository also contains libraries for other operating systems.
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)
. VERSIONS.txt lib .. bin licenses README.txt include
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 readinggetInfo
- gather information about sourcegetIOBlock
- 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)