1 function [F,I,mask] = recongrappa( varargin );
2 % [F,I,mask ] = recongrappa(Wk, Sk, Y, [opt args]);
5 % 'v', {0,1} - verbosity off/on
6 % 'kernel', string - grappa kernel size, x by y. e.g. '2x5', '4x1'
7 % 'N', (xy)-by-L matrix - grappa reconstruction parameters
8 % 'acs', array of indices - index locations to use for ACS lines
9 % 'dk', delta-k - distance between phase encode lines used by
10 % the GRAPPA kernel. default: 2
12 % This is an implementation of
13 % "Generalized autocalibrating partially parallel acquisitions"
14 % by M. A. Griswold, P. M. Jakob, et. al..
15 % Mag. Reson. Med. 47(6):1202-1210. Jun 2002
17 % Copyright 2004-2007 W. Scott Hoge (wsh032580 at proton dot me)
19 % Licensed under the terms of the MIT License
20 % (https://opensource.org/licenses/MIT)
23 % uncombined images are generated for each coil in the array, by
24 % filling in k-space lines.
27 % GRAPPA: data from all coils used to patch data in one coil
29 % coil 1 o * o * - * o *
30 % coil 2 o * o * - * o *
31 % coil 3 o * o * - * o *
32 % coil 4 o * o * x * o *
34 % *: acquired line, o: unacquired line, -: auto-callibration line
35 % x: reconstructed line
37 % S_j (k_y - m\Delta k_y ) = \sum_{l=1}^L \sum_{b=0}^{N_b-1}
38 % n(j,b,l,m) S_l(k_y - b A \Delta k_y)
40 % in a variable density sampling scheme, the center of k-space is fully
41 % sampled and can be used to determine the linear fit parameters.
43 % A - acceleration factor
44 % N_b - number of blocks used in the reconstruction
46 % N_b = 1 ----> GRAPPA = VD-AUTO-SMASH
54 acs = []; N = []; verbose=0; kernel = '2x3'; dk = 2;
55 prnt = 0; % set to '1' to output some debugging information
59 vararg = varargin(4:end);
60 for cnt=1:2:length(vararg),
61 if strcmp( vararg{cnt}, 'v' ),
62 verbose = cell2mat(vararg(cnt+1));
63 elseif strcmp( vararg{cnt}, 'N' ),
65 elseif strcmp( vararg{cnt}, 'Nbias' ),
66 Nbias = vararg{cnt+1};
67 elseif strcmp( vararg{cnt}, 'kernel' ),
68 kernel = vararg{cnt+1};
69 elseif strcmp( vararg{cnt}, 'dk' ),
71 elseif strcmp( vararg{cnt}, 'chi' ),
73 elseif strcmp( vararg{cnt}, 'acs' ),
75 elseif (strcmp( vararg{cnt}, 'report' ) | strcmp( vararg{cnt}, 'r' )),
82 acs = Y(find(d == 1));
83 % acs = acs(2:length(acs));
86 if length(size(Wk)) == 3,
87 [Wm,Wn,Wc] = size(Wk);
89 Wm = Wk(1); Wn = Wk(2); Wc = Wk(3);
92 %% zero-pad the k-space data
93 Sk = zeros( Wm, Wn, Wc );
96 % set the kernel spacings based on 'kernel' string
97 nky = str2double(kernel(1)); % should be even
101 indx0 = floor( [-(nky-1):2:(nky-1)] * dk/2 );
103 % if (nky == '2'), indx0 = [-1 1];
104 % elseif (nky == '6'), indx0 = [ -5 -3 -1 1 3 5];
105 % else % (nky == '4'), indx0 = [ -3 -1 1 3];
108 nkx = str2double(kernel(3)); % should be odd
109 indx3 = ceil((0-nkx)/2) -1 + (1:nkx); % [-2:2];
111 rptupd( sprintf(['kernel size: ' num2str(length(indx0)) 'x' num2str(length(indx3)) ';']) );
112 rptupd( sprintf([' indx0 = [' sprintf(' %d',indx0) ']; ']) );
113 rptupd( sprintf([' indx3 = [' sprintf(' %d',indx3) '];\n']) );
117 plist = zeros( length(acs), 1 );
119 for cnt2 = 1:length(acs);
120 %% check if the GRAPPA pattern...
121 indx = acs(cnt2) + indx0;
123 %% can be accomodated by the sampling pattern
124 tmp = find( Y(:)*ones(1,length(indx)) == ones(length(Y),1)*indx );
125 plist(cnt2) = ( length(tmp) == length(indx) );
127 %% use only those ACS lines that fit the GRAPPA kernel
128 acs = vec( acs(logical(plist)) ).';
129 rptupd([ ' ACS lines:' sprintf(' %d ',acs) '\n' ]);
131 rptupd('processing coil: ');
133 rptupd([' ' num2str(l)]);
134 %% determine the k-space filling coefficients for each coil:
136 %%% setup the system matrix
137 A2 = zeros( size(s,2), length(indx3)*length(indx0)*size(s,3) );
139 if size(N,2) < l, % if coefficients are not supplied
142 % A2 = zeros( size(s,2), length(indx3)*length(indx)*size(s,3) );% 20*size(s,3) );
143 % for x0=1:size(s,2),
144 % indx2 = x0 + indx3;
145 % indx2( indx2 < 1 ) = indx2( indx2 < 1 ) + size(s,2);
146 % indx2( indx2 > size(s,2) ) = indx2( indx2 > size(s,2) ) - size(s,2);
148 % A2(x0,:) = vec( permute(squeeze( Sk(indx,indx2,:)),[2 3 1 ]) ).';
152 %%% My way: (heh, 8x faster)
154 A = zeros( length(acs)*size(s,2), length(indx3)*length(indx0)*size(s,3) );
155 A2 = zeros( size(s,2), length(indx3)*length(indx0)*size(s,3) );
156 if (l==1), rptupd(['\n size(A) = ' num2str(size(A)) '\n']), end;
158 for cnt2=1:length(acs),
159 indx = acs(cnt2) + indx0;
160 for cnt=1:length(indx3),
161 y0 = mod( indx3(cnt) + [1:size(Sk,2)] , size(Sk,2) );
162 y0( y0 == 0 ) = size(Sk,2);
164 A( size(s,2)*(cnt2-1) + (1:size(s,2)), ...
165 cnt:length(indx3):size(A,2) ) = ...
166 reshape( permute(squeeze( Sk(indx,y0,:) ),[ 2 3 1 ]), ...
167 size(Sk,2), size(Sk,3)*length(indx) );
172 %%% setup the objective vector
173 b = vec( Sk( acs, :, l ).' );
175 %%% find the coefficients
176 % n = A \ b; % pinv( A, norm(A)*0.01 ) * b;
178 if (size(Nbias,1)==0), % isempty('Nbias'),
179 % n = cgsolv( A'*A, A'*b, zeros(size(A,2),1), size(A,2) );
180 [ n tt ] = bicg( A'*A + chi*eye(size(A,2)), A'*b );
182 n = cgsolv( A'*A, A'*b, Nbias(:,l), size(A,2)/4 );
185 N(:,l) = n; % store them
186 if verbose, pltcmplx( A*n, b ); keyboard; end;
189 % extract the coefficients for this coil
192 %% now go recon the missing lines of k-space:
193 mss = zeros(Wm,1); % set the missing lines index vector
196 for cnt0=1:length(mss),
197 if (mss(cnt0) == 1); continue; end;
200 if ( (min(indx) < 1) | (max(indx) > size(Sk,1))); continue; end;
202 if ( sum(sum( Y(:)*ones(size(indx)) == ones(size(Y(:)))*indx )) < length(indx) ),
206 % for x0=1:size(s,2),
207 % indx2 = x0 ; % + [-2:2];
208 % indx2( indx2 < 1 ) = indx2( indx2 < 1 ) + size(s,2);
209 % indx2( indx2 > size(s,2) ) = indx2( indx2 > size(s,2) ) - size(s,2);
212 for cnt=1:length(indx3),
213 y0 = mod( indx3(cnt) + [1:size(Sk,2)] , size(Sk,2) );
214 y0( y0 == 0 ) = size(Sk,2);
216 A2( (1:size(s,2)), cnt:length(indx3):size(A2,2) ) = ...
217 reshape( permute(squeeze( Sk(indx,y0,:) ),[ 2 3 1 ]), ...
218 size(Sk,2), size(Sk,3)*length(indx) );
220 Sk( cnt0, :, l ) = A2 * n;
221 % figure(1); imagesc( log10(abs(Sk(:,:,l)) + 1e-1) ); pause(0.5);
226 rptupd( sprintf( 'Elapsed time: %8.5g seconds.\n', etime(clock,stime) ) );
229 I = sqrt( sum(abs(ifft2(Sk)).^2,3) );
234 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
235 function rptupd( str )