line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package PDL::IO::Dcm::Plugins::MRISiemens; |
2
|
|
|
|
|
|
|
#use base 'PDL::IO::Dcm'; |
3
|
1
|
|
|
1
|
|
670
|
use Exporter; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
32
|
|
4
|
1
|
|
|
1
|
|
4
|
use PDL; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
4
|
|
5
|
1
|
|
|
1
|
|
1963
|
use PDL::NiceSlice; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
5
|
|
6
|
1
|
|
|
1
|
|
11735
|
use strict; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
20
|
|
7
|
1
|
|
|
1
|
|
9
|
use 5.10.0; |
|
1
|
|
|
|
|
2
|
|
8
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
our @ISA=qw/Exporter/; |
11
|
|
|
|
|
|
|
our @EXPORT_OK=qw/init_dims populate_header setup_dcm/; |
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
sub setup_dcm { |
14
|
0
|
|
|
0
|
1
|
|
my $opt=shift; |
15
|
0
|
0
|
|
|
|
|
$opt={} unless (ref($opt) eq 'HASH'); # ensure hash context |
16
|
|
|
|
|
|
|
# split on series number by default |
17
|
0
|
|
|
|
|
|
$$opt{id}=\&PDL::IO::Dcm::sort_series; |
18
|
0
|
|
|
|
|
|
$$opt{sort}=\&populate_header; |
19
|
0
|
|
|
|
|
|
$$opt{duplicates}=\&handle_duplicates; |
20
|
0
|
|
|
|
|
|
$$opt{delete_raw}=1; # deletes the raw_dicom structure after parsing |
21
|
0
|
|
|
|
|
|
push @PDL::IO::Dcm::key_list,'0051,100f'; |
22
|
|
|
|
|
|
|
#say join ' ',%{$opt}; |
23
|
0
|
0
|
|
|
|
|
if ($$opt{c_phase_t} ) { |
24
|
0
|
0
|
|
|
|
|
if ($$opt{c_phase_set} ) { |
25
|
0
|
|
|
|
|
|
$$opt{Dimensions}=[qw/x y z=partitions*slices T*Set*Phases Echo Channel/]; |
26
|
|
|
|
|
|
|
} else { |
27
|
0
|
|
|
|
|
|
$$opt{Dimensions}=[qw/x y z=partitions*slices T*Phases Echo Channel Set/]; |
28
|
|
|
|
|
|
|
} |
29
|
|
|
|
|
|
|
}else { |
30
|
0
|
0
|
|
|
|
|
if ($$opt{c_phase_set} ) { |
31
|
0
|
|
|
|
|
|
$$opt{Dimensions}=[qw/x y z=partitions*slices T Echo Channel Set*Phase/]; |
32
|
|
|
|
|
|
|
} else { |
33
|
0
|
|
|
|
|
|
$$opt{Dimensions}=[qw/x y z=partitions*slices T Echo Channel Phase Set /]; |
34
|
|
|
|
|
|
|
} |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
# part,sl,t,echo,coil,phase,set |
37
|
0
|
|
|
|
|
|
$$opt{dim_order}=[6,10,4,1,0,2,3]; |
38
|
|
|
|
|
|
|
$$opt{internal_dims}=[ |
39
|
|
|
|
|
|
|
# |
40
|
0
|
|
|
|
|
|
qw/x y coil echo cphase set t ? partition? chron_slice? ? slice ? some_id/]; |
41
|
|
|
|
|
|
|
# note the order since dims change by clump! |
42
|
|
|
|
|
|
|
# partitions and slices |
43
|
0
|
|
|
|
|
|
$$opt{clump_dims}=[[0,1],]; |
44
|
|
|
|
|
|
|
# phases and set, phases*set and t |
45
|
0
|
0
|
|
|
|
|
push (@{$$opt{clump_dims}},[4,5]) if $$opt{c_phase_set}; |
|
0
|
|
|
|
|
|
|
46
|
0
|
0
|
|
|
|
|
push (@{$$opt{clump_dims}},[1,4]) if $$opt{c_phase_t}; |
|
0
|
|
|
|
|
|
|
47
|
0
|
|
|
|
|
|
$opt; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
sub read_text_hdr { |
53
|
0
|
|
|
0
|
1
|
|
my $f=shift; # File |
54
|
0
|
|
|
|
|
|
my $self=shift; |
55
|
0
|
0
|
|
|
|
|
open (HDR,'<',\$f) || die "no header !"; |
56
|
0
|
|
|
|
|
|
my $l; |
57
|
|
|
|
|
|
|
#say "file $f line $l"; |
58
|
0
|
|
|
|
|
|
do {$l=; } until ($l=~/ASCCONV BEGIN/); |
|
0
|
|
|
|
|
|
|
59
|
0
|
|
|
|
|
|
while (($l=)!~/ASCCONV END/) { |
60
|
0
|
|
|
|
|
|
chomp $l; |
61
|
0
|
0
|
|
|
|
|
if ( $l) { |
62
|
0
|
|
|
|
|
|
chomp (my ($key,$val)=split /\s*=\s*/,$l); |
63
|
0
|
|
|
|
|
|
chomp($key); |
64
|
0
|
|
|
|
|
|
$key=~s/[\[\].]/_/g; |
65
|
0
|
|
|
|
|
|
$self->hdr->{ascconv}->{$key}=$val; |
66
|
|
|
|
|
|
|
} |
67
|
|
|
|
|
|
|
} |
68
|
0
|
|
|
|
|
|
close HDR; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
sub sort_protid { |
72
|
0
|
|
|
0
|
1
|
|
$_[0]->hdr->{ascconv}->{"lProtID"}; |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
sub populate_header { |
76
|
0
|
|
|
0
|
1
|
|
my $dicom =shift; |
77
|
0
|
|
|
|
|
|
my $piddle=shift; |
78
|
|
|
|
|
|
|
# The protocol is in here: |
79
|
|
|
|
|
|
|
#say "populate_header ",$_[1]->info,$_[0]->getValue('0020,0032'); |
80
|
0
|
|
|
|
|
|
read_text_hdr($dicom->getValue ('0029,1020','native'),$piddle); |
81
|
0
|
|
|
|
|
|
delete $piddle->hdr->{raw_dicom}->{'0029,1020'}; # Protocol |
82
|
0
|
|
|
|
|
|
my @ret=$dicom->getValue('0029,1010','native')=~/ICE_Dims.{92}((_?(X|\d+)){13})/s; |
83
|
0
|
|
|
|
|
|
(my $str=$ret[0])=~s/X/1/e; |
|
0
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
# to make this unique |
85
|
0
|
|
|
|
|
|
say "Instance Number ",$dicom->getValue('InstanceNumber'); |
86
|
0
|
|
0
|
|
|
|
$piddle->hdr->{dcm_key}=$dicom->getValue('InstanceNumber').'_'.($dicom->getValue('0051,100f')||0); |
87
|
0
|
|
|
|
|
|
my @d=split ('_',$str); |
88
|
0
|
|
|
|
|
|
my $iced=pdl(short,@d); #badvalue(short)/er)]); |
89
|
0
|
|
|
|
|
|
$iced--; |
90
|
0
|
|
|
|
|
|
$piddle->hdr->{dim_idx}=$iced; |
91
|
|
|
|
|
|
|
#say $piddle->hdr->{dcm_key},": ",$iced,$dicom->getValue ('0020,0032','native'); |
92
|
|
|
|
|
|
|
#say "Dims $str pos $iced"; |
93
|
0
|
|
|
|
|
|
return $str; |
94
|
|
|
|
|
|
|
} |
95
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub handle_duplicates { |
97
|
0
|
|
|
0
|
1
|
|
my $stack=shift; |
98
|
0
|
|
|
|
|
|
my $dcm=shift; |
99
|
0
|
|
|
|
|
|
my $opt=shift; |
100
|
|
|
|
|
|
|
"This entry (". $dcm->hdr->{dim_idx}->($$opt{dim_order}). |
101
|
0
|
|
|
|
|
|
max ($stack->(,,list $dcm->hdr->{dim_idx}->($$opt{dim_order}))). |
102
|
|
|
|
|
|
|
") is already set! This should not happen, please file a bug report!\n"; |
103
|
|
|
|
|
|
|
} |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
sub init_dims { |
106
|
1
|
|
|
1
|
|
6
|
use PDL::NiceSlice; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
6
|
|
107
|
0
|
|
|
0
|
1
|
|
my $self=shift; |
108
|
0
|
|
|
|
|
|
my $opt=shift; |
109
|
|
|
|
|
|
|
# we need these modules, return undef otherwise. |
110
|
0
|
0
|
|
|
|
|
require PDL::Dims || return; |
111
|
0
|
0
|
|
|
|
|
require PDL::Transform || return; |
112
|
0
|
|
|
|
|
|
PDL::Dims->import(qw/is_equidistant dmin dmax vals hpar dinc initdim dimsize drot idx diminfo /); |
113
|
0
|
|
|
|
|
|
say "init_dims: ",$self->hdr->{dicom}->{Rows} ; |
114
|
0
|
|
|
|
|
|
say "init_dims: hpar ",hpar($self,'dicom','Rows'); |
115
|
0
|
|
|
|
|
|
PDL::Transform->import(qw/t_linear/); |
116
|
|
|
|
|
|
|
#say diminfo ($self),$self->hdr->{ascconv}->{sGroupArray_asGroup_1__nSize}; |
117
|
|
|
|
|
|
|
# center=inner(rot*scale,dim/2)+Image Position (Patient) |
118
|
|
|
|
|
|
|
# xf=t_linear(matrix=>Pixel Scale*$rot->transpose,post=>Image Position (Patient)) |
119
|
0
|
0
|
|
|
|
|
if (hpar($self,'ascconv','sGroupArray_asGroup_1__nSize')){ |
120
|
0
|
|
|
|
|
|
warn "Multiple slice groups, support dubious!"; |
121
|
|
|
|
|
|
|
} |
122
|
1
|
|
|
1
|
|
2778
|
use PDL::NiceSlice; |
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
7
|
|
123
|
0
|
|
|
|
|
|
my $v=zeroes(3); |
124
|
0
|
|
0
|
|
|
|
$v(0,).=hpar($self,'ascconv','sSliceArray_asSlice_0__sPosition_dSag') ||0; #x |
125
|
0
|
|
0
|
|
|
|
$v(1,).=hpar($self,'ascconv','sSliceArray_asSlice_0__sPosition_dCor') ||0; #y |
126
|
0
|
|
0
|
|
|
|
$v(2,).=hpar($self,'ascconv','sSliceArray_asSlice_0__sPosition_dTra') ||0; #z |
127
|
0
|
|
|
|
|
|
say $v; |
128
|
|
|
|
|
|
|
say "hpar: pos ",hpar($self,'dicom','Image Position (Patient)'), |
129
|
0
|
|
|
|
|
|
$self->hdr->{dicom}->{'Image Position (Patient)'}; |
130
|
0
|
|
|
|
|
|
say "init_dims: ",hpar($self,'dicom','Rows'); |
131
|
0
|
|
|
|
|
|
my $pos_d=(hpar($self,'dicom','Image Position (Patient)'))->flat->(:5)->reshape(3,2); |
132
|
0
|
|
0
|
|
|
|
my $ir=hpar($self,'ascconv','sSliceArray_asSlice_0__dInPlaneRot') ||0; #radiant |
133
|
0
|
|
|
|
|
|
my $or=pdl(hpar($self,'dicom','Image Orientation (Patient)'))->flat->(:5) |
134
|
|
|
|
|
|
|
->reshape(3,2)->transpose; # |
135
|
0
|
|
|
|
|
|
my $pe_dir=hpar($self,'dicom','In-plane Phase Encoding Direction'); |
136
|
|
|
|
|
|
|
# Scaling |
137
|
|
|
|
|
|
|
# Rotation |
138
|
0
|
|
|
|
|
|
my $srot=zeroes(3,3); |
139
|
0
|
|
|
|
|
|
$srot(:1,).=$or; |
140
|
0
|
|
|
|
|
|
$srot(2,;-).=norm($pos_d(,1;-)-$pos_d(,0;-)); |
141
|
0
|
0
|
|
|
|
|
$srot(2,;-).=pdl[0,0,1] unless any ($srot(2,;-)); |
142
|
|
|
|
|
|
|
#say "spatial rotation $srot"; |
143
|
0
|
|
|
|
|
|
$pos_d=$pos_d(,0;-); |
144
|
|
|
|
|
|
|
# Calculate and initialise the transformation |
145
|
0
|
|
|
|
|
|
my @ors=qw/Cor Sag Tra/; |
146
|
0
|
|
|
|
|
|
$self->hdr->{orientation}=$ors[maximum_ind($srot(2;-))]; # normal vector lookup |
147
|
|
|
|
|
|
|
my $pe=$self->hdr->{dicom}->{"In-plane Phase Encoding Direction"} |
148
|
0
|
|
0
|
|
|
|
||$self->hdr->{dicom}->{"InPlanePhaseEncodingDirection"}; |
149
|
0
|
0
|
|
|
|
|
if ($self->hdr->{orientation} eq 'Tra'){ # transversal slice |
150
|
0
|
|
|
|
|
|
say $self->hdr->{orientation}. " Orientation"; |
151
|
0
|
|
|
|
|
|
$self->hdr->{sl}='z'; |
152
|
0
|
0
|
|
|
|
|
if ($pe eq 'COL'){ |
153
|
0
|
|
|
|
|
|
$self->hdr->{ro}='x'; |
154
|
0
|
|
|
|
|
|
$self->hdr->{pe}='y'; |
155
|
|
|
|
|
|
|
} else { |
156
|
0
|
|
|
|
|
|
$self->hdr->{ro}='y'; |
157
|
0
|
|
|
|
|
|
$self->hdr->{pe}='x'; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
} |
160
|
0
|
0
|
|
|
|
|
if ($self->hdr->{orientation} eq 'Cor'){ # coronal slice |
161
|
0
|
|
|
|
|
|
$self->hdr->{sl}='y'; |
162
|
0
|
0
|
|
|
|
|
if ($pe eq 'COL') { |
163
|
0
|
|
|
|
|
|
$self->hdr->{ro}='x'; |
164
|
0
|
|
|
|
|
|
$self->hdr->{pe}='z'; |
165
|
|
|
|
|
|
|
} else { |
166
|
0
|
|
|
|
|
|
$self->hdr->{ro}='z'; |
167
|
0
|
|
|
|
|
|
$self->hdr->{pe}='x'; |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
} |
170
|
0
|
0
|
|
|
|
|
if ($self->hdr->{orientation} eq 'Sag'){ # sagittal slice |
171
|
0
|
|
|
|
|
|
$self->hdr->{sl}='x'; |
172
|
0
|
0
|
|
|
|
|
if ($pe eq 'COL') { |
173
|
0
|
|
|
|
|
|
$self->hdr->{ro}='y'; |
174
|
0
|
|
|
|
|
|
$self->hdr->{pe}='z'; |
175
|
|
|
|
|
|
|
} else { |
176
|
0
|
|
|
|
|
|
$self->hdr->{ro}='z'; |
177
|
0
|
|
|
|
|
|
$self->hdr->{pe}='y'; |
178
|
|
|
|
|
|
|
} |
179
|
|
|
|
|
|
|
} |
180
|
0
|
|
|
|
|
|
my $s=zeroes(3); # matrix size |
181
|
0
|
|
|
|
|
|
my $fov=zeroes(3); # FOV |
182
|
0
|
|
|
|
|
|
$fov(0).=$self->hdr->{ascconv}->{sSliceArray_asSlice_0__dReadoutFOV}; |
183
|
0
|
|
|
|
|
|
$fov(1).=$self->hdr->{ascconv}->{sSliceArray_asSlice_0__dPhaseFOV}; |
184
|
0
|
0
|
|
|
|
|
if ($pe =~ 'COL') { |
185
|
0
|
|
0
|
|
|
|
$s(0).=$self->hdr->{dicom}->{Width}||$self->hdr->{dicom}->{Columns}; |
186
|
0
|
|
0
|
|
|
|
$s(1).=$self->hdr->{dicom}->{Height}||$self->hdr->{dicom}->{Rows}; |
187
|
0
|
|
|
|
|
|
say "COL! $s"; |
188
|
|
|
|
|
|
|
} else { |
189
|
0
|
|
0
|
|
|
|
$s(1).=$self->hdr->{dicom}->{Width}||$self->hdr->{dicom}->{Columns}; |
190
|
0
|
|
0
|
|
|
|
$s(0).=$self->hdr->{dicom}->{Height}||$self->hdr->{dicom}->{Rows}; |
191
|
|
|
|
|
|
|
#$fov(1).=$self->hdr->{ascconv}->{sSliceArray_asSlice_0__dReadoutFOV}; |
192
|
|
|
|
|
|
|
#$fov(0).=$self->hdr->{ascconv}->{sSliceArray_asSlice_0__dPhaseFOV}; |
193
|
|
|
|
|
|
|
} |
194
|
0
|
|
|
|
|
|
say "PE $pe $s $fov " ; |
195
|
|
|
|
|
|
|
$self->hdr->{'3d'}=1 if (($self->hdr->{dicom}->{MRAcquisitionType}|| |
196
|
0
|
0
|
0
|
|
|
|
hpar($self,'dicom','MR Acquisition Type')) eq '3D'); # 3D |
197
|
0
|
0
|
|
|
|
|
if ($self->hdr->{'3d'}) { |
198
|
0
|
|
|
|
|
|
$s(2).=$self->hdr->{ascconv}->{'sKSpace_lImagesPerSlab'} ; |
199
|
0
|
|
|
|
|
|
$fov(2).=$self->hdr->{ascconv}->{sSliceArray_asSlice_0__dThickness}; |
200
|
|
|
|
|
|
|
} else { |
201
|
0
|
|
|
|
|
|
$s(2).=$self->hdr->{ascconv}->{'sSliceArray_lSize'}; |
202
|
0
|
|
|
|
|
|
$fov(2).=$self->hdr->{dicom}->{"Spacing Between Slices"}*$s(2); |
203
|
0
|
|
|
|
|
|
say "FOV $fov matrix $s"; |
204
|
|
|
|
|
|
|
} |
205
|
0
|
0
|
|
|
|
|
$s(2).=1 if ($s(2)<1); |
206
|
0
|
|
|
|
|
|
my $rot=identity($self->ndims); |
207
|
0
|
|
|
|
|
|
my $inc_d=zeroes(3); |
208
|
|
|
|
|
|
|
#say "Pixel Spacing", hpar($self,'dicom','Pixel Spacing'); |
209
|
0
|
|
|
|
|
|
$inc_d(:1).=hpar($self,'dicom','Pixel Spacing')->(:1;-); |
210
|
0
|
|
|
|
|
|
$inc_d(2).=$fov(2,0)/$s(2,0); |
211
|
|
|
|
|
|
|
#say $srot; |
212
|
0
|
|
|
|
|
|
$rot(:2,:2).=$srot; |
213
|
0
|
|
|
|
|
|
say "FOV $fov matrix $s, pixels $inc_d"; |
214
|
0
|
0
|
|
|
|
|
barf "dims don't fit! $s vs. ",$self->shape->(:2) if any($self->shape->(:2)-$s); |
215
|
|
|
|
|
|
|
#say "Rot: $rot"; |
216
|
0
|
|
|
|
|
|
initdim($self,'x',size=>$s(0),min=>sclr($pos_d(0)),inc=>sclr($inc_d(0)),unit=>'mm'); |
217
|
0
|
|
|
|
|
|
initdim($self,'y',size=>$s(1),min=>sclr($pos_d(1)),inc=>sclr($inc_d(1)),unit=>'mm'); |
218
|
0
|
|
|
|
|
|
initdim($self,'z',size=>$s(2),rot=>$rot,min=>sclr($pos_d(2)),inc=>sclr($inc_d(2)),unit=>'mm',); |
219
|
0
|
|
|
|
|
|
say "initdim for x,y,z done."; |
220
|
0
|
|
|
|
|
|
say "after init dim ",(diminfo ($self)); |
221
|
0
|
|
|
|
|
|
say "size $s min $pos_d inc $inc_d rot $rot"; |
222
|
0
|
|
|
|
|
|
idx($self,'x',dimsize($self,'x')/2); |
223
|
0
|
|
|
|
|
|
idx($self,'y',dimsize($self,'y')/2); |
224
|
0
|
|
|
|
|
|
idx($self,'z',dimsize($self,'z')/2); |
225
|
0
|
|
|
|
|
|
say "orientation : ",hpar($self,'orientation'),diminfo ($self); |
226
|
|
|
|
|
|
|
# other dimensions |
227
|
0
|
|
|
|
|
|
for my $n (3..$#{$$opt{Dimensions}}) { # x,y,z are handled above |
|
0
|
|
|
|
|
|
|
228
|
0
|
|
|
|
|
|
my $dim=$$opt{Dimensions}->[$n]; |
229
|
0
|
|
|
|
|
|
print "Init Dim $dim - $n\n"; |
230
|
0
|
|
|
|
|
|
my $str=('(0),' x ($n-2)).','.('(0),' x ($#{$$opt{Dimensions}}-$n)); |
|
0
|
|
|
|
|
|
|
231
|
0
|
|
|
|
|
|
say "$str "; |
232
|
0
|
0
|
|
|
|
|
if ($dim eq 'Echo') { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
233
|
|
|
|
|
|
|
# my $str=('(0),' x ($n-2)).','.('(0),' x ($#{$$opt{Dimensions}}-$n)); |
234
|
0
|
|
|
|
|
|
initdim ($self,'echo',unit=>'us', |
235
|
|
|
|
|
|
|
vals=>[list (hpar($self,'dicom','Echo Time')->($str))]); |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
elsif ($dim eq 'T') { |
238
|
|
|
|
|
|
|
# my $str=('(0),' x ($n-2)).','.('(0),' x ($#{$$opt{Dimensions}}-$n)); |
239
|
0
|
|
|
|
|
|
my $t=hpar($self,'dicom','Acquisition Time')->($str); |
240
|
0
|
0
|
|
|
|
|
if (is_equidistant($t,0.003)) { |
241
|
0
|
|
|
|
|
|
initdim ($self,'t',unit=>'s',min=>sclr($t(0)),max=>sclr($t(-1))); |
242
|
0
|
|
|
|
|
|
say "T min ",dmin($self,'t')," max ",dmax($self,'t')," inc ",dinc($self,'t'), $t; |
243
|
|
|
|
|
|
|
} else { |
244
|
0
|
|
|
|
|
|
initdim ($self,'t',unit=>'s',vals=>[list($t)]); |
245
|
0
|
|
|
|
|
|
say "T values :",vals ($self,'t'); |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
} elsif ($dim =~ /Channel/) { |
248
|
0
|
|
0
|
|
|
|
my $coil=hpar($self,'dicom','0051,100f')||'combined'; |
249
|
0
|
0
|
|
|
|
|
if ($self->dim($n)>1) { |
250
|
0
|
|
|
|
|
|
initdim ($self,'channel',vals=>[hpar($self,'dicom','0051,100f')->flat->(:2)]); |
251
|
|
|
|
|
|
|
} else { |
252
|
0
|
|
|
|
|
|
initdim ($self,'channel',vals=>[$coil, size=>1]); |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
} elsif ($dim =~ /Set/) { |
255
|
0
|
|
|
|
|
|
initdim ($self,'set'); # This can be anything, no further info easily available |
256
|
|
|
|
|
|
|
} elsif ($dim =~ /Phase/) { |
257
|
0
|
|
|
|
|
|
my $t=hpar($self,'dicom','Trigger Time'); |
258
|
0
|
|
|
|
|
|
say $t->info; |
259
|
0
|
|
|
|
|
|
$t=$t($str); |
260
|
0
|
|
|
|
|
|
say $t; |
261
|
0
|
0
|
|
|
|
|
if (is_equidistant($t)) { |
262
|
0
|
|
|
|
|
|
initdim ($self,'cphase',unit=>'ms',min=>sclr($t(0)),max=>sclr($t(-1))); |
263
|
0
|
|
|
|
|
|
say "Trigger min ",dmin($self,'cphase')," max ",dmax($self,'cphase')," inc ",dinc($self,'cphase'), $t; |
264
|
0
|
|
|
|
|
|
say "Trigger ",vals ($self,'cphase'); |
265
|
|
|
|
|
|
|
} else { |
266
|
0
|
|
|
|
|
|
initdim ($self,'cphase',unit=>'ms',vals=>[list($t)]); |
267
|
0
|
|
|
|
|
|
say "Trigger values :",vals ($self,'cphase'); |
268
|
|
|
|
|
|
|
} |
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
} |
271
|
0
|
|
|
|
|
|
my $mat=drot($self) x stretcher (pdl(dinc($self))); |
272
|
0
|
|
|
|
|
|
$mat=$mat->transpose ;#if ($pe_dir =~ /COL/); |
273
|
|
|
|
|
|
|
#say $mat; |
274
|
0
|
|
|
|
|
|
my $xf=t_linear(matrix=>$mat,post=>$pos_d(,0;-)); |
275
|
0
|
|
|
|
|
|
say "inc ",dinc ($self); |
276
|
0
|
|
|
|
|
|
say diminfo($self); |
277
|
0
|
|
|
|
|
|
hpar($self,'init_transform','matrix',$mat); |
278
|
0
|
|
|
|
|
|
hpar($self,'init_transform','post',$pos_d(,0;-)); |
279
|
|
|
|
|
|
|
#barf "initdim fails!" unless ($#{dimname($self)}>2); |
280
|
|
|
|
|
|
|
} |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
=head1 Specific handling of Simenes MRI data |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
Key 0029,1010 is the Siemens specific field that contains the ICE |
286
|
|
|
|
|
|
|
miniheaders with dimension information - and position in matrix |
287
|
|
|
|
|
|
|
0029,1020 is deleted from the header, it is big, containing the whole |
288
|
|
|
|
|
|
|
protocol. The important part, the Siemens protocol ASCCONV part, is stored in |
289
|
|
|
|
|
|
|
the ascconv key, see read_text_hdr. |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
=head1 FUNCTIONS |
293
|
|
|
|
|
|
|
|
294
|
|
|
|
|
|
|
=head2 handle_duplicates |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
What to do if two images with the same position in the stack arrive. Throws an |
297
|
|
|
|
|
|
|
error, atm. Should handle duplicate exports |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
=head2 init_dims |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
provides support for PDL::Dims. Useful in combination with PDL::IO::Sereal to |
302
|
|
|
|
|
|
|
have a fully qualified data set. |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
=head2 populate_header |
305
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
Here happens the vendor/modallity specific stuff like parsing private fields. |
307
|
|
|
|
|
|
|
It is required to return a position vector in the series' piddle. |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
=head2 read_text_hdr |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
parses the ASCCONV part of Siemens data header into the ascconv field of the |
312
|
|
|
|
|
|
|
piddle header. All special characters except [a-z0-9]i are converted to _ -- no |
313
|
|
|
|
|
|
|
quoting of hash keys required! You don't need to load this yourself. |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
=head2 setup_dcm |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
sets useful options for this modality. |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
=head2 sort_protid |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
alternative to split based on lProtID (matches raw data key). To activate, |
322
|
|
|
|
|
|
|
after running setup_dcm, point option id to \&sort_protid. |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=head1 Specific options |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
=over |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=item Nifti |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
Do we want Nifti output? May be used by your plugin to apply additional steps, |
331
|
|
|
|
|
|
|
eg. more clumps, reorders, setting header fields ... |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
=item c_phase_t |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
Serialize phase and t dimensions |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
=back |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
=cut |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
1; |