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. For general usage, the specific stuff is moved to its own plugin. Each plugin needs to support a setup_dcm() and a populate_header() function.

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:

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 always at the beginning and are 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

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.