File Coverage

blib/lib/PDL/IO/Dcm.pm
Criterion Covered Total %
statement 43 243 17.7
branch 1 84 1.1
condition 0 14 0.0
subroutine 15 22 68.1
pod 7 7 100.0
total 66 370 17.8


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             #
3             package PDL::IO::Dcm;
4              
5             =head1 NAME
6              
7             PDL::IO::Dcm - Reads dicom files, sorts them and stores the result into piddles with headers
8              
9             =head1 VERSION
10              
11             Version 0.9
12              
13             =cut
14              
15             our $VERSION = '0.9_200';
16              
17              
18             =head1 SYNOPSIS
19              
20             This is inteded to read and sort dicom images created by medical imaging devices.
21              
22             Either use something like the following from within your module/application
23              
24             # loads all dicom files in this directory
25             # $id is a code reference returning e.g. the Series Number
26             my $dcms=load_dcm_dir($dir,$id);
27             die "no data!" unless (keys %$dcms);
28             print "Read data; ProtIDs: ",join ', ',keys %$dcms,"\n";
29             # sort all individual dicoms into a hash of piddles.
30             my $data=parse_dcms($dcms);
31              
32             or use the read_dcm.pl script to convert dicom files in a directory to serealised
33             piddles (PDL::IO::Sereal) or NIFTI files with separate text headers (PDL::IO::Nifti).
34              
35             This software is tailored to Siemens MRI data based on the author's needs. For
36             general usage, the read_dcm function should and probably will be moved to
37             vendor/modality specific plugin modules in future releases.
38              
39             =head1 Some notes on Dicom fields and how they are stored/treated
40              
41             The image data field is stored as the piddle, the other dicom
42             elements are stored in the header under the raw_dicom key.
43              
44             The Siemens protocol ASCCONV part is stored in the ascconv key.
45              
46             Key 0029,1010 is the Siemens specific field that contains the ICE
47             miniheaders with dimension information - and position in matrix
48             0029,1020 is deleted from the header, it is big, containing the whole
49             protocol. The important part is parsed into ascconv.
50              
51             Keys are parsed into a hash under the dicom key using the DicomPack module(s)
52             to unpack.
53              
54             The header fields IceDims and IcePos are used for sorting datasets. The field
55             Dimensions lists the sorted names of dimensions.
56              
57             Piddles are created for each lProtID or Series Number value.
58              
59              
60             =head1 SUBROUTINES/METHODS
61              
62             =head2 is_equal ($dcm1,$dcm2,$pattern)
63              
64             This is used to check if two dicoms can be stacked based on matrix size, orientation and pixel spacing.
65              
66             If $pattern matches /d/, only dims are checked
67              
68             =head2 load_dcm_dir ( $dir,\%options)
69              
70             reads all dicom files in a dicrectory and returns a hash of piddles containing
71             sorted N-D data sets.
72              
73             Fields in the options hash include:
74              
75             =over
76              
77             =item id:
78              
79             Uses a code reference to access the field by which to split. See read_dcm.pl for details. Currently, the ascconv field lProtID or dicom Series Number are used as keys.
80              
81             =item sp:
82              
83             Split slice groups, otherwise they are stacked together if xy-dims match, even transposed.
84              
85             =back
86              
87              
88             =head2 parse_dcms
89              
90             Parses and sorts a hash of hashes of dicoms (such as returned by load_dcm_dir)
91             based on lProtID and the ICE_Dims field in 0029_1010. Returns a hash of piddles
92             (lProtID).
93              
94             =head2 unpack_field
95              
96             unpacks dicom fields and walks subfield structures recursively.
97              
98             =head2 sort_series
99              
100             Groups dicom files based on their series number. If data within the series
101             don't fit, the outcome depends on the split option. If set, it will always
102             produce several piddles, appending a, b, c, etc.; if not, transposition is tried,
103             ignoring Pixel Spacing and Image Rotation. Only if this fails, data is split.
104              
105             =head2 read_dcm ($file, \%options)
106              
107             reads a dicom file and creates a piddle-with-header structure.
108              
109             =head2 printStruct
110              
111             This is used to generate human readable and parsable text from the headers.
112              
113             =head1 TODO
114              
115             write tests!
116              
117             Generalise to other modalities. This will be done based on request or as needed.
118              
119             =cut
120              
121 1     1   13551 use PDL;
  1         8  
  1         3  
122 1     1   153316 use PDL::NiceSlice;
  1         1  
  1         9  
123 1     1   2304 use List::MoreUtils; # qw{any};
  1         6690  
  1         4  
124 1     1   837 use Data::Dumper;
  1         4451  
  1         49  
125 1     1   427 use DicomPack::IO::DicomReader;
  1         30972  
  1         38  
126 1     1   702 use Storable qw/dclone/;
  1         2309  
  1         73  
127 1     1   8 use DicomPack::DB::DicomTagDict qw/getTag getTagDesc/;
  1         1  
  1         61  
128 1     1   5 use DicomPack::DB::DicomVRDict qw/getVR/;
  1         2  
  1         50  
129 1     1   5 use Exporter;
  1         1  
  1         36  
130             #use PDL::IO::Nifti;
131 1     1   6 use strict;
  1         2  
  1         907  
132             #use PDL::IO::Sereal;
133             #use 5.10.0;
134              
135             our @ISA=qw/Exporter/;
136             our @EXPORT_OK=qw/read_dcm parse_dcms load_dcm_dir printStruct/;
137              
138             my @key_list=("Instance Number",,'Window Center','Content Time',
139             'Nominal Interval','Instance Creation Time','Largest Image Pixel Value',
140             'Trigger Time','Window Width','Acquisition Time','Smallest Image Pixel Value',
141             );
142              
143              
144             sub sort_series {
145 0     0 1   my $ret=$_[0]->hdr->{dicom}->{"Series Number"};
146 0           $ret=~ s/^\s+|\s+$//g; $ret;
  0            
147             }
148              
149             # copied and modified from stackoverflow or perlmonks thread (can't remember atm)
150             sub printStruct {
151 0     0 1   my ($struct,$structName,$pre)=@_;
152             # print "-----------------\n" unless (defined($pre));
153             #
154 0           my $res;
155             #if (!ref($struct)){ # $struct is a scalar.
156 0 0         if (ref($struct) eq "ARRAY") { # Struct is an array reference
    0          
    0          
157             #return ("ARRAY(".scalar(@$struct).")") if (@$struct>100);
158 0           for(my$i=0;$i<@$struct;$i++) {
159 0 0         if (ref($struct->[$i]) eq "HASH") {
    0          
    0          
160 0           $res.=printStruct($struct->[$i],$structName."->[$i]",$pre." ");
161             } elsif (ref($struct->[$i]) eq "ARRAY") { # contents of struct is array ref
162 0 0         $res.= "$structName->"."[$i]: ()\n" if (@{$struct->[$i]}==0);
  0            
163 0           my $string = printStruct($struct->[$i],$structName."->[$i]",$pre." ");
164 0 0         $res.= "$structName->"."[$i]: $string\n" if ($string);
165             } elsif (ref($struct->[$i]) eq "PDL") { # contents of struct is array ref
166 0           $res.= "$structName->"."[$i]: ".(join (' ',list ($struct->[$i])))."\n";
167             } else { # contents of struct is a scalar, just print it.
168            
169 0           $res.= "$structName->"."[$i]: $struct->[$i]\n";
170             }
171             }
172             #return($res);
173             } elsif (ref($struct) eq "HASH"){ # $struct is a hash reference or a scalar
174 0           foreach (sort keys %{$struct}) {
  0            
175 0 0         if (ref($struct->{$_}) eq "HASH") {
    0          
    0          
176 0           $res.=printStruct($struct->{$_},$structName."->{$_}",$pre." ");
177             } elsif (ref($struct->{$_}) eq "ARRAY") { # contents of struct is array ref
178 0           my $string = printStruct($struct->{$_},$structName."->{$_}",$pre." ");
179 0 0         $res.= "$structName->"."{$_}: $string\n" if ($string);
180             } elsif (ref($struct->{$_}) eq "PDL") { # contents of struct is array ref
181 0           $res.= "$structName->"."{$_}: ".(join (' ',list($struct->{$_})))."\n";
182             } else { # contents of struct is a scalar, just print it.
183 0           $res.= "$structName->"."{$_}: $struct->{$_}\n";
184             }
185             }
186             #return($res);
187             } elsif (ref ($struct) eq 'PDL') {
188 0           $res.= "$structName: ".(join (' ',list($struct)))."\n";
189             } else {
190 0           $res.= "$structName: $struct\n";
191             }
192             #print "------------------\n" unless (defined($pre));
193 0           return($res);
194             }
195              
196             sub unpack_field{
197 0     0 1   my $id=shift;
198 0           my $tag=shift;
199 0           my $packstring;
200 0           my $value=shift;
201 0           my $return; #=shift;
202             #say "id $id value? ", ref( $value) unless ($id=~/0029/);
203 0 0         if (ref($value) eq 'ARRAY') {
    0          
204 0           my @vs=();
205 0           for my $n ($#$value) {
206 0           push @vs,unpack_field ("$id/$n",getTag("$id/$n"),$$value[$n],$return);
207             }
208 0           $return=\@vs;
209             } elsif (ref ($value) eq 'HASH') {
210 0           my %vh=();
211 0           for my $v (keys %$value) {
212             #(my $w=$v)=~s/([0-9a-fA-F]{4}),([0-9a-fA-F]{4})/$1_$2/ ;
213             #say "key $v ";
214 0           $vh{$v}=unpack_field("$id/$v",getTag("$id/$v"),$$value{$v},$return);
215             #say "hash $id/$v: $vh{$v} " unless $id=~/0029/;
216             }
217 0           $return=\%vh;
218             } else {
219 0           my $vr=substr($value,0,2);
220 0   0       $packstring=join ('',(eval {getVR($vr)->{type}}||'a').'*');
221             #say "ID $id tag $tag ps $packstring ";
222 0 0 0       if ($vr eq 'XX' and defined $tag) {
223             #say "ID $id, Tag $$tag{desc} ", %{$$tag{vr}};
224 0   0       $packstring=join '',map {((getVR($_))->{type}||'a').'*'}
225 0           keys %{$$tag{vr}};
  0            
226             }
227 0           $return=unpack ($packstring,substr($value,3,));
228             # split vector string into list
229             #($value=[split /\\/,$value]) if $id =~ /0020,003[27]/;
230             # position and orientation
231             #($value=[split /\\/,$value]) if $id =~ /0028,0030/; # pixel size
232             #say "Image Rows $vr $packstring $value " if ($$tag{desc} eq 'Rows');
233             }
234             #say "ID $id value $value";
235 0           $return;
236             }
237              
238             sub read_dcm {
239 0     0 1   my $file=shift;
240 0           my $opt=shift; #options
241 0   0       my $dcm=DicomPack::IO::DicomReader->new($file) || return;
242 0           my $h=unpack('S',substr ($dcm->getValue('Rows','native'),3,2));
243 0           my $w=unpack('S',substr ($dcm->getValue('Columns','native'),3,2));
244 0           my $data=$dcm->getValue('PixelData','native');
245 0 0         return (undef ) unless defined $data;
246 0           my $datatype= (substr($data,0,2));
247             #say "datatype $datatype";
248 0 0         my $pdl=zeroes(ushort,$w,$h) if ($datatype =~/OW|XX/);
249 0           $pdl->make_physical;
250 0           ${$pdl->get_dataref}=substr($data,3);
  0            
251 0           $pdl->upd_data;
252 0           $pdl->hdr->{raw_dicom}=$dcm->getDicomField;
253 1     1   6 no PDL::NiceSlice;
  1         1  
  1         11  
254             #say "populate header ",$$opt{dims},join ' ',%{$opt};
255 0           my $dims=$$opt{dims}->($dcm,$pdl); # call to vendor/modality specific stuff
256 0   0       $pdl->hdr->{IceDims}=$dims || die "No Ice Dims ",$file; #pdl->hdr->{raw_dicom}->{'0029,1010'}; #[split '_',$dims{$pid}=~s/X/0/r];
257 0           delete $pdl->hdr->{raw_dicom}->{'7fe0,0010'}; # Pixel data
258 0           for my $id (keys %{$pdl->hdr->{raw_dicom}}) {
  0            
259 0           my $tag=getTag($id);
260 0           my $value=unpack_field($id,$tag,$dcm->getValue($id,'native'));
261             #say "id $id v $value";
262 0 0         if (defined $tag) {
263             #say "ID $id, Tag $$tag{desc} ", %{$$tag{vr}};
264             #$packstring=join '',map {((getVR($_))->{type}||'a').'*'}
265             #keys %{$$tag{vr}};
266             #say "Packstring $packstring";
267             #$value=unpack($packstring,$dcm->getValue($id),'native');
268             #say "Vaule $value";
269 0           $pdl->hdr->{dicom}->{$tag->{desc}}=$value;
270             } else {
271             }
272 0           $pdl->hdr->{dicom}->{$id} #=~s/([0-9a-fA-F]{4}),([0-9a-fA-F]{4})/$1_$2/r}
273             =$value;
274             } # for loop over dicom ids
275 0 0         delete $pdl->hdr->{raw_dicom} if $$opt{delete_raw};
276 0           return $pdl;
277             }
278             sub is_equal {
279 0     0 1   my $a=shift;
280 0           my $b=shift;
281 0           my $opt=shift;
282             #say "dims ", any $a->shape-$b->shape,', ', # they have equal dimensions
283             #"spacing ",$a->hdr->{dicom}->{'Pixel Spacing'} ,' ne ', $b->hdr->{dicom}->{'Pixel Spacing'},', ',
284             #"orientation ",$a->hdr->{dicom}->{'Image Orientation (Patient)'} ,' ne ', $b->hdr->{dicom}->{'Image Orientation (Patient)'};
285 0 0         return if (any ($a->shape-$b->shape)); # they have equal dimensions
286             #say "is_equal: dims ok";
287 0 0         return 1 if ($opt =~/d/);
288 0 0         return if $a->hdr->{dicom}->{'Pixel Spacing'} ne $b->hdr->{dicom}->{'Pixel Spacing'};
289             #say "is_equal: spacing ok";
290 0 0         return if $a->hdr->{dicom}->{'Image Orientation (Patient)'} ne $b->hdr->{dicom}->{'Image Orientation (Patient)'};
291             #say "is_equal: orientation ok";
292 0           1;
293             }
294              
295             sub load_dcm_dir {
296 0     0 1   my %dcms; #([]);
297             my @pid;
298 0           my $dname=shift;
299 0           my %dims;
300 0           my $opt=shift; # field by which to split
301 0           my $id=$$opt{id};
302 0           my $sp=$$opt{split};
303 0           my $n=0;
304 0           my %refs; # reference images for each stack
305 0 0         opendir (my $dir, $dname) ||die "cannot open directory!";
306 0           for my $file (readdir ($dir)) {
307 0 0         next unless (-f "$dname/$file"); # =~m/\.dcm$|\.IMA$/;
308             #say "file $file";
309 0           my $p=read_dcm("$dname/$file",$opt);
310 0 0         eval{$p->isa('PDL')} ||next;
  0            
311 0           $n++;
312 1     1   326 no PDL::NiceSlice;
  1         2  
  1         4  
313 0           my $pid=$id->($p); # Call to subroutine reference
314             #say "ID $pid Instance number ",$p->hdr->{dicom}->{'Instance Number'};
315 0 0         $dcms{$pid}={} unless ref $dcms{$pid};
316 0           my $ref =$refs{$pid};
317             #say "ref ID: ",$id->($ref)," ref Instance number ",$ref->hdr->{dicom}->{'Instance Number'},
318             #$ref->info,$p->info, "diff? ",is_equal($ref,$p);
319 0 0         if (defined $ref) {
320 0 0         unless ( is_equal($ref,$p )) {
321 0 0 0       if ( !$sp and is_equal($ref,$p->transpose,'d')) {
322             #say "Split? $sp; ", ( !$sp and is_equal($ref,$p->transpose,'d'));
323 0           $p->hdr->{tp}=1;
324             } else {
325             #say "Difference! $sp";
326 0           my $flag=0;
327 0           my $n='a';
328 0           my $nid;
329 0           do {
330 0           $nid=$id->($p).$n;
331 0 0         if (ref $dcms{$nid} eq 'HASH'){ # group
332 0           for my $r2 (values %{$dcms{$nid}}){
  0            
333 0           $flag=is_equal($r2,$p);
334             # say "r2 vs. p id $nid ",$r2->info,$p->info;
335 0 0         last unless $flag;
336             }
337             } else {
338 0           $dcms{$nid}={};
339 0           $pid=$nid;
340 0           $flag=1;
341             }
342 0           $n++;
343             } until $flag;
344 0           $pid=$nid;
345             }
346             }
347             } # defined $ref
348 1     1   136 use PDL::NiceSlice;
  1         1  
  1         5  
349 0 0         unless (grep (/^$pid$/,@pid)) {
350             #say "PID: $pid";
351 0           $dims{$pid}=zeroes(short,13);
352 0           push @pid,$pid;
353 0           $refs{$pid}=$p;
354             }
355             #say "pos ",$p->hdr->{dicom}->{'0020,0032'}=~s/\\/ /r;
356             #say "orientation ",$p->hdr->{dicom}->{'0020,0037'}=~s/\\/ /r;
357             #say "Spacing ",$p->hdr->{dicom}->{'0028,0030'}=~s/\\/ /r;
358             #say "IceDims ",$p->hdr->{IceDims};
359             #say "$n Series $pid IceDims ",$p->hdr->{IceDims};
360 0           (my $str=$p->hdr->{IceDims})=~s/X/1/e;
  0            
361 0           my @d=split ('_',$str);
362 0           my $iced=pdl(short,@d); #badvalue(short)/er)]);
363             #say "$file IceDims ",$iced;
364             #$iced->badflag(1);
365 0           $dims{$pid}.=$dims{$pid}*($dims{$pid}>=$iced)+$iced*($iced>$dims{$pid});
366 0           $p->hdr->{IcePos}=$iced--;
367 0           $dcms{$pid}->{$p->hdr->{IceDims}}=$p; # if ($p->isa('PDL')); # and $pid == $p->hdr->{ascconv}->{lProtID});
368             }
369 0           for my $id (@pid) {
370 0           $dcms{$id}->{dims}=$dims{$id}->copy;
371 0           print "Set dims: id $id, $dims{$id}\n";
372             }
373 0           \%dcms;
374             }
375              
376              
377              
378             sub parse_dcms {
379 0     0 1   my %dcms=%{shift()}; # reference to hash of
  0            
380 0           my %data;
381             #my (%tes,);
382 0           for my $pid (sort keys %dcms) {
383 0           my %stack=%{$dcms{$pid}};
  0            
384             #next unless (ref $stack{dims} eq 'HASH');
385             #say keys %stack;
386 0           my $dims =$stack{dims};
387 0 0         die "No dims $pid " unless eval {$dims->isa('PDL')};
  0            
388 0           delete $stack{dims};
389 0           my $ref=$stack{(keys %stack)[0]};
390             #my $z=$ref->hdr->{ascconv}->{sSliceArray_lSize};
391 0           my $x=$ref->hdr->{dicom}->{Columns} ;
392 0 0         die "No $x ",$ref->info unless $x;
393 0           my $y=$ref->hdr->{dicom}->{Rows};
394             #print "ID: $pid dims $dims transpose? ",$ref->hdr->{tp},"\n";
395             # dims: coil echo phase set t ? partition? slice? ? slice ? some_id
396 0           my $order=pdl[6,7,4,1,0,2,3];
397 0 0         if ($ref->hdr->{tp}) { $data{$pid}=zeroes(ushort,$y,$x,$dims($order));}
  0            
398 0           else { $data{$pid}=zeroes(ushort,$x,$y,$dims($order));}
399 0           my $header=dclone($ref->gethdr); # populate the header
400 0           $header->{diff}={};
401 0           $header->{Dimensions}=[qw/x y z t echo channel set/];
402 0           for my $key (@key_list) {
403 0           $header->{dicom}->{$key}=zeroes(list $dims($order));
404             #$header->{dicom}->{$key}.=$ref->hdr->{dicom}->{$key};
405             #say "$key ",$header->{dicom}->{$key}->info;
406             }
407 0           $header->{dicom}->{'Image Orientation (Patient)'}=zeroes(6,list $dims($order));
408 0           $header->{dicom}->{'Image Position (Patient)'}=zeroes(3,list $dims($order));
409 0           $header->{dicom}->{'Pixel Spacing'}=zeroes(2,list $dims($order));
410 0           for my $dcm (values %stack) {
411             #say $data{$pid}->info,list( $dcm->hdr->{IcePos}->($order));
412             #say "$x $y ",$ref->info;
413             #say "ID $pid: Transpose? ",$dcm->hdr->{tp},$dcm->info;
414 0 0         if ($dcm->hdr->{tp}) {
415 0           $data{$pid}->(,,list $dcm->hdr->{IcePos}->($order)).=$dcm->transpose;}
416 0           else {$data{$pid}->(,,list $dcm->hdr->{IcePos}->($order)).=$dcm;}
417 0           for my $key (@key_list) {
418             #say "setting $key ",$dcm->hdr->{IcePos}->($order) ;
419             $header->{dicom}->{$key}->(list $dcm->hdr->{IcePos}->($order))
420 0           .=$dcm->hdr->{dicom}->{$key};
421             }
422             $header->{dicom}->{'Image Orientation (Patient)'}
423             ->(,list $dcm->hdr->{IcePos}->($order))
424 0           .=pdl (split /\\/,$dcm->hdr->{dicom}->{'Image Orientation (Patient)'});
425             $header->{dicom}->{'Pixel Spacing'}
426             ->(,list $dcm->hdr->{IcePos}->($order))
427 0           .=pdl (split /\\/,$dcm->hdr->{dicom}->{'Pixel Spacing'});
428             $header->{dicom}->{'Image Position (Patient)'}
429             ->(,list $dcm->hdr->{IcePos}->($order))
430 0           .=pdl (split /\\/,$dcm->hdr->{dicom}->{'Image Position (Patient)'});
431 0           for my $field (keys %{$dcm->hdr->{dicom}}) {
  0            
432 0 0         if ($dcm->hdr->{dicom}->{$field} ne $ref->hdr->{dicom}->{$field}) {
433             $header->{diff}->{$field}={}
434 0 0         unless ref ($header->{diff}->{$field});
435             $header->{diff}->{$field}->{$dcm->hdr->{IceDims}}=
436 0           $dcm->hdr->{dicom}->{$field};
437             }
438             }
439             } # for ... values %stack
440 0           my $ind=whichND(maxover maxover ($data{$pid})); # actually populated fields!
441             #$data{$pid}->hdrcpy(1);
442 0           for my $ax (0..$ind->dim(0)-1) {
443 0           $data{$pid}=$data{$pid}->dice_axis($ax+2,$ind($ax)->uniq); # compact the data!
444             $header->{dicom}->{'Image Position (Patient)'}
445 0           =$header->{dicom}->{'Image Position (Patient)'}->dice_axis($ax+1,$ind($ax)->uniq);
446             $header->{dicom}->{'Image Orientation (Patient)'}
447 0           =$header->{dicom}->{'Image Orientation (Patient)'}->dice_axis($ax+1,$ind($ax)->uniq);
448             $header->{dicom}->{'Pixel Spacing'}
449 0           =$header->{dicom}->{'Pixel Spacing'}->dice_axis($ax+1,$ind($ax)->uniq);
450 0           for my $key (@key_list) {
451 0           $header->{dicom}->{$key}=$header->{dicom}->{$key}->dice_axis($ax,$ind($ax)->uniq);
452             }
453 0           for my $val (values %{$header->{diff}}) {
  0            
454 0 0         $val=$val->dice_axis($ax,$ind($ax)->uniq) if (ref ($val) =~ /PDL/);
455             }
456             }
457             #$data{$pid}->hdrcpy(0);
458             #say "ind $ind";
459             #say "position ",$header->{dicom}->{'Image Position (Patient)'}->info;
460             #say "orientationn ",$header->{dicom}->{'Image Orientation (Patient)'}->info;
461             #say "spacing ",$header->{dicom}->{'Pixel Spacing'}->info;
462             $header->{dicom}->{'Image Position (Patient)'}
463 0           =$header->{dicom}->{'Image Position (Patient)'}->clump(1,2)->clump(5,6)->copy;
464             $header->{dicom}->{'Image Orientation (Patient)'}
465 0           =$header->{dicom}->{'Image Orientation (Patient)'}->clump(1,2)->clump(5,6)->copy;
466             $header->{dicom}->{'Pixel Spacing'}
467 0           =$header->{dicom}->{'Pixel Spacing'}->clump(1,2)->clump(5,6)->copy;
468             #say "A position ",$header->{dicom}->{'Image Position (Patient)'}->info;
469             #say "A orientationn ",$header->{dicom}->{'Image Orientation (Patient)'}->info;
470             #say "A spacing ",$header->{dicom}->{'Pixel Spacing'}->info;
471 0           for my $key (@key_list) {
472             #say "key $key ",$header->{dicom}->{$key}->info;
473 0           $header->{dicom}->{$key}=$header->{dicom}->{$key}->clump(0,1)->clump(4,5);
474             }
475 0           for my $val (values %{$header->{diff}}) {
  0            
476 0 0         $val=$val->clump(0,1)->clump(4,5) if (ref ($val) =~ /PDL/);
477             }
478             #say "The following keys differ from ref:\n\t",join ", ",sort keys (%{$header->{diff}});
479             #say Dumper $header->{diff};
480             #say $data{$pid}->info;
481             #say $header->{dicom}->{Rows};
482             #$data{$pid}->hdrcpy(1);
483             # serialise partitions/slices and phases/sets
484 0           $data{$pid}=$data{$pid}->clump(2,3)->clump(6,7);
485 0           $data{$pid}->sethdr(dclone($header));
486             #say "ID $pid ",$data{$pid}->hdr->{dicom}->{'Pixel Spacing'}->squeeze;
487             #say $data{$pid}->info;
488             #say $data{$pid}->info;
489             #say $data{$pid}->hdr->{dicom}->{Rows};
490             } # for my $pid ...
491 0           \%data;
492             }
493              
494              
495              
496             BEGIN {
497 1 50   1   10893 if ($_[0] eq q/-d/) {
498 0         0 require Carp;
499 0         0 $SIG{__DIE__} = sub {print Carp::longmess(@_); die;};
  0         0  
  0         0  
500             }
501             }
502             1;
503              
504             =head1 LICENSE AND COPYRIGHT
505              
506             Copyright 2016 Albrecht Ingo Schmid.
507              
508             This program is free software; you can redistribute it and/or modify it
509             under the terms of the the Artistic License (2.0). You may obtain a
510             copy of the full license at:
511              
512             L
513              
514             Any use, modification, and distribution of the Standard or Modified
515             Versions is governed by this Artistic License. By using, modifying or
516             distributing the Package, you accept this license. Do not use, modify,
517             or distribute the Package, if you do not accept this license.
518              
519             If your Modified Version has been derived from a Modified Version made
520             by someone other than you, you are nevertheless required to ensure that
521             your Modified Version complies with the requirements of this license.
522              
523             This license does not grant you the right to use any trademark, service
524             mark, tradename, or logo of the Copyright Holder.
525              
526             This license includes the non-exclusive, worldwide, free-of-charge
527             patent license to make, have made, use, offer to sell, sell, import and
528             otherwise transfer the Package with respect to any patent claims
529             licensable by the Copyright Holder that are necessarily infringed by the
530             Package. If you institute patent litigation (including a cross-claim or
531             counterclaim) against any party alleging that the Package constitutes
532             direct or contributory patent infringement, then this Artistic License
533             to you shall terminate on the date that such litigation is filed.
534              
535             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
536             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
537             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
538             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
539             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
540             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
541             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
542             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
543              
544              
545             =cut
546              
547 1     1   9 __END__