🔄 SPM Two-Pass Realignment: Complete Flow
USER RUNS: batch_realign.m
↓
📄 batch_realign.m
Line 28: 'rtm', 1,... % Override default!
⚠️ SPM default is rtm=0, but we set rtm=1 → enables TWO-PASS
Line 53: spm_realign_asl(P, reaFlags);
↓ Passes: P (images), reaFlags (rtm=1)
📄 spm_realign_asl.m (Main Function)
Line 95: def_flags = struct(...'rtm',0,...)
Default rtm=0, but gets overwritten by reaFlags.rtm=1
Line 123: P{1} = realign_series(P{1}, flags);
☑️ This function does BOTH Pass 1 AND Pass 2!
Line 129: P{1} = cleanandsave_parameters(P{1}, ref);
☑️ Called AFTER both passes → saves rp_*.txt
↓ Calls realign_series()
🔧 SUBFUNCTION: realign_series(P, flags)
🔄 PASS 1: Align to First Volume (Lines 270-331)
Line 220: V = smooth_vol(P(1),...); % First vol = reference
Line 270-276: if flags.rtm,
count = ones(size(b));
ave = G; % Start accumulating mean
grad1 = dG1; grad2 = dG2; grad3 = dG3;
end;
Line 278: spm_progress_bar(...'Registering Images');
Line 281: for i=2:length(P), % Skip first volume!
Line 288: [y1,y2,y3] = coords([0 0 0 0 0 0], P(1).mat, P(i).mat,...);
Reference = P(1).mat (first volume)
Line 316-327: if flags.rtm,
count(msk) = count(msk) + 1;
ave(msk) = ave(msk) + G*sc; % Accumulate mean!
grad1/2/3(msk) = grad1/2/3(msk) + dG1/2/3*sc;
end;
STATUS AFTER PASS 1:
• P(1).mat = identity (unchanged)
• P(2-90).mat = transformations relative to vol 1
• ave, grad1-3, count = accumulated mean data
↓
⚡ CHECKPOINT (Line 333)
if ~flags.rtm, return; end;
❌ If rtm=0: STOP here (one pass only)
✅ If rtm=1: Continue to Pass 2 (our case!)
↓ Continue...
🔄 PASS 2: Re-align to Mean (Lines 334-382)
Line 335-338:
M = P(1).mat;
A0 = make_A(M, x1,x2,x3, grad1./count, grad2./count, grad3./count, wt, lkp);
b = (ave./count); % This is the MEAN image!
Line 344: spm_progress_bar(...'Registering Images to Mean');
☑️ Different message from Pass 1!
Line 345: for i=1:length(P), % Starts at 1! All volumes!
Line 351: [y1,y2,y3] = coords([0 0 0 0 0 0], M, P(i).mat,...);
Reference = M (mean), NOT P(1).mat anymore!
STATUS AFTER PASS 2 (before re-centering):
• P(1-90).mat = ALL transformations relative to MEAN
• First volume now has non-zero motion params
Line 385-391: ⚠️ Misleading comment!
% "aligning to first image" ← WRONG! Re-centering!
M = M/P(1).mat;
for i=1:length(P)
P(i).mat = M*P(i).mat; % Re-center: avg = 0
end
FINAL STATUS AFTER RE-CENTERING:
• Average motion = 0
• P(1).mat ≈ [0,0,0,0,0,0] (first vol close to mean position)
• P(2-90).mat = motion relative to centered mean
↓ Returns to main function
💾 SUBFUNCTION: cleanandsave_parameters(V, ref) (Lines 514-537)
Line 515: fname = [...'rp_' ... '.txt'];
Line 521-525: for j=1:n,
qq = spm_imatrix(V(j).mat/V(1).mat);
V(j).mat = Pass 2 results!
Q(j,:) = qq(1:6); % Extract x,y,z,pitch,roll,yaw
clQ(j,:) = qq(1:6);
end;
Line 526-530: Clean label/control effects (ASLtbx-specific)
for j=1:6
clQ(:,j) = refval - ref/(ref'*ref)*ref'*refval;
clQ(:,j) = clQ(:,j) - clQ(1,j);
end
Line 535: Q = cat(2, Q, clQ); % 12 cols: [Pass2_orig Pass2_clean]
Line 536: save(fname, 'Q', '-ascii'); % SAVE rp_*.txt
✅ rp_*.txt contains PASS 2 (mean-based) results!
✅ Saved ONCE after both passes complete
✅ No overwriting - single save at end
↓
📁 OUTPUT: rp_ASL.txt
90 rows × 12 columns
Columns 1-6: Pass 2 original params
Columns 7-12: Pass 2 cleaned params
📊 KEY INSIGHTS
🔢 Two Passes:
• Pass 1: Align to first vol, compute mean
• Pass 2: Re-align ALL vols to mean
📍 References Change:
• Pass 1: P(1).mat (first volume)
• Pass 2: M (mean from Pass 1)
🔄 Loop Differences:
• Pass 1: i=2:N (skip first)
• Pass 2: i=1:N (all volumes)
💾 rp_*.txt Timing:
• Created ONCE after both passes
• Contains Pass 2 results only
Why first row is zeros:
Re-centering (line 388-391) makes average motion = 0. First volume happens to be close to mean position, so after re-centering it gets [0,0,0,0,0,0]. This is NOT because first volume was the reference!
Proof that mean is reference:
Motion parameters for SAME volumes differ between Stage 1 (62 vol) and Stage 3 (90 vol) by 0.002mm. If first volume were reference, parameters would be IDENTICAL. Different means → different Pass 2 → different rp_*.txt ✓