NAME
PDL::IO::Dcm - Reads dicom files, sorts them and stores the result into piddles with headers
SYNOPSIS
This module is inteded to read and sort dicom images created by medical imaging devices. Either use something like the following from within your module/application
use PDL::IO::Dcm::Plugins::Primitive qw/setup_dcm/;
my %options=();
...
setup_dcm(\%options);
# loads all dicom files in this directory
my $dcms=load_dcm_dir($dir,\%options);
die "no data!" unless (keys %$dcms);
print "Read data; IDs: ",join ', ',keys %$dcms,"\n";
# sort all individual dicoms into a hash of piddles.
my $data=parse_dcms($dcms,\%options);
... # do something with your data.
or use the read_dcm.pl script to convert dicom files in a directory to serealised piddles (PDL::IO::Sereal) or NIFTI files with separate text headers (PDL::IO::Nifti).
Plugins
Modality/vendor specific treatment and sorting is done by plugins, to be installed under the PDL::IO::Dcm::Plugins name space. Using Primitive should get you started, data will be grouped based on dicom series numbers and sorted by instance number. If you need something more sophisticated, take a look at the MRISiemens plugin.
This software is based on the use case of Siemens MRI data based on the author's needs. Specific handling of file formats, data, header fields is moved to its own plugin.
Each plugin needs to support a etup_dcm() function that takes a reference to an options hash. Important keys are:
create_data() sets up the piddle holding the data and setes the dimensions in options' field.
read_dcm() function should and probably will be moved to vendor/modality specific plugin modules in future releases.
Some notes on Dicom fields and how they are stored/treated
The image data field is stored as the piddle, the other dicom elements are first stored in the header under the raw_dicom key. After parsing, most fields are accessible under the dicom key. The raw_dicom structure is then deleted, use the delete_raw option if you want to change this.
Keys are parsed into a hash under the dicom key using the DicomPack module(s) to unpack. Piddles are created for data grouped based on the id option. The header fields dcm_key and dim_idx are used for sorting datasets.
Options
The behaviour of the module's routines are controlled through options, stored in a hash. Your plugin may add additional keys as needed. Fields in the options hash used by this module are:
- parser (rquired) - A function reference to a parser in the plugin. This function has to provide dimensions information (dim_idx) key in the piddle header.
- clump_dims
-
these are clumped together to reduce dimensions, required by e.g. Nifti (max. 7).
- delete_raw
-
flag controlling whether the unparsed dicom fields under raw_dicom should be retained; default no.
- dim_order
-
order in which dimensions are stored, used to reorder the data. xy are typically the first two and are often not counted.
- Dimensions
-
list ref to names of expected dims. xy are left out. Should be set by your plugin to help interpret data.
- duplicates
-
a code ref executed if two images have identical positions in stack, e.g. same Series Number Instance Number, this can happen.
- id
-
code ref expecting to return a key to group files; defaults to \&sort_series.
- internal_dims
-
raw dimension list before any clumping. This is not used at the moment but allows for description of the input dimensions.
- sort
-
code ref typically set to your plugin's populate_header routine. This is called to set dim_idx and dcm_key for each file
- sp:
-
Split slice groups, otherwise they are stacked together if xy-dims match, even transposed.
SUBROUTINES/METHODS
clump_data
Utitlity to clump a piddle over clump_dims option field, takes an offset
create_image_data
to be called from create_data() for image data.
fill_image_data
to be called from fill_data() for image data.
image_parser
to be called from parser() for image data.
is_equal ($dcm1,$dcm2,$pattern)
This is used to check if two dicoms can be stacked based on matrix size, orientation and pixel spacing.
If $pattern matches /d/, only dims are checked
load_dcm_dir ( $dir,\%options)
reads all dicom files in a dicrectory and returns a hash of hashes of piddles based on the sort option and dcm_key.
parse_dcms ($hashref,\$options)
Parses and sorts a hash of hashes of dicoms (such as returned by load_dcm_dir) based on dcm_key and dim_idx. Returns a hash of piddles.
unpack_field
unpacks dicom fields and walks subfield structures recursively.
sort_series
Groups dicom files based on their series number. If data within the series don't fit, the outcome depends on the split option. If set, it will always produce several piddles, appending a, b, c, etc.; if not, transposition is tried, ignoring Pixel Spacing and Image Rotation. Only if this fails, data is split.
read_dcm ($file, \%options)
reads a dicom file and creates a piddle-with-header structure.
printStruct
This is used to generate human readable and parsable text from the headers.
TODO
write tests!
Since all data in a directory are loaded into memeory before sorting, this may cause memory issues. At the moment, you only option is to split the files into several directories, if you face problems.
Generalise to other modalities. This will be done based on data available, request or as needed.
LICENSE AND COPYRIGHT
Copyright 2016 Albrecht Ingo Schmid.
This program is free software; you can redistribute it and/or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at:
http://www.perlfoundation.org/artistic_license_2_0
Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license.
If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license.
This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder.
This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed.
Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.