Develop Custom Datastore for DICOM Data
This example shows how to develop a custom datastore that supports writing operations. The
datastore is named DICOMDatastore
because it supports DICOM ® (Digital Imaging and Communications in
Medicine) data, which is an international standard for medical imaging
information.
Developing Custom Datastores
The topic Develop Custom Datastore describes the general
process for creating a custom datastore, as well as the specific requirements to add
different pieces of functionality. There are a variety of superclasses you can subclass from
depending on what pieces of functionality you need (parallel evaluation, writing operations,
shuffling, and so on). In particular, you can add support for writing operations by
subclassing from matlab.io.datastore.FileWritable
. However, for the broadest set of writing
functionality, you must also subclass from matlab.io.datastore.FoldersPropertyProvider
, which adds a
Folders
property to the datastore. The complete requirements to add
writing support to a custom datastore are covered in Add Support for Writing Data.
Class Definition
This table contains code and explanations for the DICOMDatastore
class.
classdef DICOMDatastore < matlab.io.Datastore & ... matlab.io.datastore.FileWritable & ... matlab.io.datastore.FoldersPropertyProvider | Class Header
|
properties Files matlab.io.datastore.FileSet end | Public Properties
|
properties (Constant) SupportedOutputFormats = ... [matlab.io.datastore.ImageDatastore.SupportedOutputFormats, "dcm"]; DefaultOutputFormat = "dcm"; end |
|
methods(Access = public) function myds = DICOMDatastore(location) % The class constructor to set properties of the datastore. myds.Files = matlab.io.datastore.FileSet(location, ... "IncludeSubfolders", true); populateFoldersFromLocation(myds,location); reset(myds); end | Public Methods The public
methods section defines common datastore methods that the class uses to manipulate
data. Public methods are externally accessible, so class users of
The constructor
|
function tf = hasdata(myds) %HASDATA Returns true if more data is available. % Return logical scalar indicating availability of data. % This method should be called before calling read. This % is an abstract method and must be implemented by the % subclasses. hasdata is used in conjunction with read to % read all the data within the datastore. tf = hasNextFile(myds.Files); end | The |
function [data, info] = read(myds) %READ Read data and information about the extracted data. % Return the data extracted from the datastore in the % appropriate form for this datastore. Also return % information about where the data was extracted from in % the datastore. Both the outputs are required to be % returned from the read method and can be of any type. % info is recommended to be a struct with information % about the chunk of data read. data represents the % underlying class of tall, if tall is created on top of % this datastore. This is an abstract method and must be % implemented by the subclasses. % In this example, the read method reads data from the % datastore using a custom reader function, MyFileReader, % which takes the resolved filenames as input. if ~hasdata(myds) error("No more data to read.\nUse reset method to " ... + "reset the datastore to the start of the data. Before " ... + "calling the read method, check if data is available " ... + "to read by using the hasdata method."); end file = nextfile(myds.Files); try data = dicomread(file.Filename); catch ME error("%s has failed", file.FileName); end info.FileSize = size(data); info.Filename = file.Filename; end | |
function reset(myds) %RESET Reset to the start of the data. % Reset the datastore to the state where no data has been % read from it. This is an abstract method and must be % implemented by the subclasses. % In this example, the datastore is reset to point to the % first file (and first partition) in the datastore. reset(myds.Files); end | |
function frac = progress(myds) %PROGRESS Percentage of consumed data between 0.0 and 1.0. % Return fraction between 0.0 and 1.0 indicating progress as a % double. The provided example implementation returns the % ratio of the index of the current file from FileSet % to the number of files in FileSet. A simpler % implementation can be used here that returns a 1.0 when all % the data has been read from the datastore, and 0.0 % otherwise. % % See also matlab.io.Datastore, read, hasdata, reset, readall, % preview. frac = progress(myds.Files); end end | |
methods(Access = protected) function dsCopy = copyElement(myds) %COPYELEMENT Create a deep copy of the datastore % Create a deep copy of the datastore. We need to call % copy on the datastore's property FileSet because it is % a handle object. Creating a deep copy allows methods % such as readall and preview, which call the copy method, % to remain stateless. dsCopy = copyElement@matlab.mixin.Copyable(myds); dsCopy.Files = copy(myds.Files); end | Protected Methods Protected
methods redefine methods that were inherited by the class, and they are only
accessible to The protected
|
function tf = write(myds, data, writeInfo, outFmt, varargin) if outFmt == "dcm" dicomwrite(data, writeInfo.SuggestedOutputName, varargin{:}); else write@matlab.io.datastore.FileWritable(myds, data, ... writeInfo, outFmt, varargin{:}); end tf = true; end | The protected |
function files = getFiles(myds) files = myds.Files.FileInfo.Filename; end end | The protected |
end | End the |
Using the DICOMDatastore
Class
After you implement the DICOMDatastore
class, you can use the constructor
to create a new DICOMDatastore
object that references the location of a set
of DICOM files. For example, if you have DICOM files in the folder
C:\Data\DICOM\series-000001\
:
ds = DICOMDatastore("C:\Data\DICOM\series-000001")
ds = DICOMDatastore with properties: Files: [1×1 matlab.io.datastore.FileSet] SupportedOutputFormats: ["png" "jpg" "jpeg" "tif" "tiff" "dcm"] DefaultOutputFormat: "dcm" Folders: {'C:\Data\DICOM\series-000001'}
Class users of DICOMDatastore
have access to these public
methods:
methods(ds)
Methods for class DICOMDatastore: DICOMDatastore copy isPartitionable preview read reset writeall combine hasdata isShuffleable progress readall transform Methods of DICOMDatastore inherited from handle.
In particular, with support for writeall
, you can write the files to a
new
location:
writeall(ds,"C:\Data2\DICOM\")
C:\Data2\DICOM\series-000001
.For general information on authoring classes in MATLAB®, see Classes.
See Also
matlab.io.Datastore
| matlab.io.datastore.FileWritable
| matlab.io.datastore.FoldersPropertyProvider