def run_linear(self, image): n_slice, n_ref_rows, n_fe = self.refShape N1 = image.shape[-1] n_conj_rows = n_ref_rows - self.xleave # form the S[u]S*[u+1] array: inv_ref = ifft(image.ref_data[0]) inv_ref = inv_ref[:,:-self.xleave,:] * \ N.conjugate(inv_ref[:,self.xleave:,:]) # Adjust the percentile parameter to reflect the percentage of # points that actually have data (not the pctage of all points). # Do this by determining the fraction of points that pass an # intensity threshold masking step. ir_mask = build_3Dmask(N.abs(inv_ref), 0.1) self.percentile *= ir_mask.sum() / (n_conj_rows * n_slice * n_fe) # partition the phase data based on acquisition order: # pos_order, neg_order define which rows in a slice are grouped # (remember not to count the lines contaminated by artifact!) pos_order = (self.ref_alpha[:n_conj_rows] > 0).nonzero()[0] neg_order = (self.ref_alpha[:n_conj_rows] < 0).nonzero()[0] # in Varian scans, the phase of the 0th product seems to be # contaminated.. so throw it out if there is at least one more # even-odd product # case < 3 ref rows: can't solve problem # case 3 ref rows: p0 from (0,1), n0 from (1,2) # case >=4 ref rows: p0 from (2,3), n0 from (1,2) (can kick line 0) # if the amount of data can support it, throw out p0 if len(pos_order) > 1: pos_order = pos_order[1:] phs_vol = unwrap_ref_volume(inv_ref) phs_mean, q1_mask = mean_and_mask(phs_vol[:, pos_order, :], phs_vol[:, neg_order, :], self.percentile, self.good_slices) ### SOLVE FOR THE SYSTEM PARAMETERS if not self.shear_correct: if self.force_6p_soln: # solve for a1,a2,a3,a4,a5,a6, keep (a1,a3,a5) coefs = solve_phase_6d(phs_mean, q1_mask) coefs = coefs[0::2] else: coefs = solve_phase_3d(phs_mean, q1_mask) print coefs return correction_volume_3d(self.volShape, self.alpha, *coefs) else: coefs = solve_phase_6d(phs_mean, q1_mask) print coefs return correction_volume_6d(self.volShape, self.alpha, self.beta, *coefs)
def run_linear(self, image): n_slice, n_ref_rows, n_fe = self.refShape N1 = image.shape[-1] n_conj_rows = n_ref_rows - self.xleave # form the S[u]S*[u+1] array: inv_ref = ifft(image.ref_data[0]) inv_ref = inv_ref[:, : -self.xleave, :] * N.conjugate(inv_ref[:, self.xleave :, :]) # Adjust the percentile parameter to reflect the percentage of # points that actually have data (not the pctage of all points). # Do this by determining the fraction of points that pass an # intensity threshold masking step. ir_mask = build_3Dmask(N.abs(inv_ref), 0.1) self.percentile *= ir_mask.sum() / (n_conj_rows * n_slice * n_fe) # partition the phase data based on acquisition order: # pos_order, neg_order define which rows in a slice are grouped # (remember not to count the lines contaminated by artifact!) pos_order = (self.ref_alpha[:n_conj_rows] > 0).nonzero()[0] neg_order = (self.ref_alpha[:n_conj_rows] < 0).nonzero()[0] # in Varian scans, the phase of the 0th product seems to be # contaminated.. so throw it out if there is at least one more # even-odd product # case < 3 ref rows: can't solve problem # case 3 ref rows: p0 from (0,1), n0 from (1,2) # case >=4 ref rows: p0 from (2,3), n0 from (1,2) (can kick line 0) # if the amount of data can support it, throw out p0 if len(pos_order) > 1: pos_order = pos_order[1:] phs_vol = unwrap_ref_volume(inv_ref) phs_mean, q1_mask = mean_and_mask( phs_vol[:, pos_order, :], phs_vol[:, neg_order, :], self.percentile, self.good_slices ) ### SOLVE FOR THE SYSTEM PARAMETERS if not self.shear_correct: if self.force_6p_soln: # solve for a1,a2,a3,a4,a5,a6, keep (a1,a3,a5) coefs = solve_phase_6d(phs_mean, q1_mask) coefs = coefs[0::2] else: coefs = solve_phase_3d(phs_mean, q1_mask) print coefs return correction_volume_3d(self.volShape, self.alpha, *coefs) else: coefs = solve_phase_6d(phs_mean, q1_mask) print coefs return correction_volume_6d(self.volShape, self.alpha, self.beta, *coefs)
def run_centric(self, image): # centric sampling for epidw goes [0,..,31] then [-1,..,-32] # in index terms this is [32,33,..,63] + [31,30,..,0] # solving for angle(S[u]S*[u+1]) is equal to the basic problem for u>=0 # for u<0: # angle(S[u]S*[u+1]) = 2[sign-flip-terms]*(-1)^(u+1) + [shear-terms] # = -(2[sign-flip-terms]*(-1)^u - [shear-terms]) # so by flipping the sign on the phs means data, we can solve for the # sign-flipping (raster) terms and the DC offset terms with the same # equations. n_slice, n_ref_rows, n_fe = self.refShape n_vol_rows = self.volShape[-2] n_conj_rows = n_ref_rows - 2 # this is S[u]S*[u+1].. now with n_ref_rows-1 rows inv_ref = ifft(image.ref_data[0]) inv_ref = inv_ref[:, :-1, :] * N.conjugate(inv_ref[:, 1:, :]) # Adjust the percentile parameter to reflect the percentage of # points that actually have data (not the pctage of all points). # Do this by determining the fraction of points that pass an # intensity threshold masking step. ir_mask = build_3Dmask(N.abs(inv_ref), 0.1) self.percentile *= ir_mask.sum() / (n_conj_rows * (n_slice * n_fe)) # in the lower segment, do NOT grab the n_ref_rows/2-th line.. # its product spans the two segments cnj_upper = inv_ref[:, n_ref_rows / 2:, :].copy() cnj_lower = inv_ref[:, :n_ref_rows / 2 - 1, :].copy() phs_evn_upper = unwrap_ref_volume(cnj_upper[:, 0::2, :]) phs_odd_upper = unwrap_ref_volume(cnj_upper[:, 1::2, :]) # 0th phase diff on the upper trajectory is contaminated by eddy curr, # throw it out if possible: if phs_evn_upper.shape[-2] > 1: phs_evn_upper = phs_evn_upper[:, 1:, :] phs_evn_lower = unwrap_ref_volume(cnj_lower[:, 0::2, :]) phs_odd_lower = unwrap_ref_volume(cnj_lower[:, 1::2, :]) # 0th phase diff on downward trajectory (== S[u]S*[u+1] for u=-30) # is contaminated too if phs_evn_lower.shape[-2] > 1: phs_evn_lower = phs_evn_lower[:, :-1, :] phs_mean_upper, q1_mask_upper = \ mean_and_mask(phs_evn_upper, phs_odd_upper, self.percentile, self.good_slices) phs_mean_lower, q1_mask_lower = \ mean_and_mask(phs_evn_lower, phs_odd_lower, self.percentile, self.good_slices) if not self.shear_correct: # for upper (u>=0), solve normal SVD if self.force_6p_soln: coefs = solve_phase_6d(phs_mean_upper, q1_mask_upper) coefs = coefs[0::2] else: coefs = solve_phase_3d(phs_mean_upper, q1_mask_upper) print coefs theta_upper = correction_volume_3d(self.volShape, self.alpha, *coefs) # for lower (u < 0), solve with negative data if self.force_6p_soln: coefs = solve_phase_6d(-phs_mean_lower, q1_mask_lower) coefs = coefs[0::2] else: coefs = solve_phase_3d(-phs_mean_lower, q1_mask_lower) print coefs theta_lower = correction_volume_3d(self.volShape, self.alpha, *coefs) theta_lower[:, n_vol_rows / 2:, :] = theta_upper[:, n_vol_rows / 2:, :] return theta_lower else: # for upper (u>=0), solve normal SVD coefs = solve_phase_6d(phs_mean_upper, q1_mask_upper) print coefs theta_upper = correction_volume_6d(self.volShape, self.alpha, self.beta, *coefs) # for lower (u < 0), solve with negative data coefs = solve_phase_6d(-phs_mean_lower, q1_mask_lower) print coefs theta_lower = correction_volume_6d(self.volShape, self.alpha, self.beta, *coefs) theta_lower[:, n_vol_rows / 2:, :] = theta_upper[:, n_vol_rows / 2:, :] return theta_lower
def run_centric(self, image): # centric sampling for epidw goes [0,..,31] then [-1,..,-32] # in index terms this is [32,33,..,63] + [31,30,..,0] # solving for angle(S[u]S*[u+1]) is equal to the basic problem for u>=0 # for u<0: # angle(S[u]S*[u+1]) = 2[sign-flip-terms]*(-1)^(u+1) + [shear-terms] # = -(2[sign-flip-terms]*(-1)^u - [shear-terms]) # so by flipping the sign on the phs means data, we can solve for the # sign-flipping (raster) terms and the DC offset terms with the same # equations. n_slice, n_ref_rows, n_fe = self.refShape n_vol_rows = self.volShape[-2] n_conj_rows = n_ref_rows - 2 # this is S[u]S*[u+1].. now with n_ref_rows-1 rows inv_ref = ifft(image.ref_data[0]) inv_ref = inv_ref[:, :-1, :] * N.conjugate(inv_ref[:, 1:, :]) # Adjust the percentile parameter to reflect the percentage of # points that actually have data (not the pctage of all points). # Do this by determining the fraction of points that pass an # intensity threshold masking step. ir_mask = build_3Dmask(N.abs(inv_ref), 0.1) self.percentile *= ir_mask.sum() / (n_conj_rows * (n_slice * n_fe)) # in the lower segment, do NOT grab the n_ref_rows/2-th line.. # its product spans the two segments cnj_upper = inv_ref[:, n_ref_rows / 2 :, :].copy() cnj_lower = inv_ref[:, : n_ref_rows / 2 - 1, :].copy() phs_evn_upper = unwrap_ref_volume(cnj_upper[:, 0::2, :]) phs_odd_upper = unwrap_ref_volume(cnj_upper[:, 1::2, :]) # 0th phase diff on the upper trajectory is contaminated by eddy curr, # throw it out if possible: if phs_evn_upper.shape[-2] > 1: phs_evn_upper = phs_evn_upper[:, 1:, :] phs_evn_lower = unwrap_ref_volume(cnj_lower[:, 0::2, :]) phs_odd_lower = unwrap_ref_volume(cnj_lower[:, 1::2, :]) # 0th phase diff on downward trajectory (== S[u]S*[u+1] for u=-30) # is contaminated too if phs_evn_lower.shape[-2] > 1: phs_evn_lower = phs_evn_lower[:, :-1, :] phs_mean_upper, q1_mask_upper = mean_and_mask(phs_evn_upper, phs_odd_upper, self.percentile, self.good_slices) phs_mean_lower, q1_mask_lower = mean_and_mask(phs_evn_lower, phs_odd_lower, self.percentile, self.good_slices) if not self.shear_correct: # for upper (u>=0), solve normal SVD if self.force_6p_soln: coefs = solve_phase_6d(phs_mean_upper, q1_mask_upper) coefs = coefs[0::2] else: coefs = solve_phase_3d(phs_mean_upper, q1_mask_upper) print coefs theta_upper = correction_volume_3d(self.volShape, self.alpha, *coefs) # for lower (u < 0), solve with negative data if self.force_6p_soln: coefs = solve_phase_6d(-phs_mean_lower, q1_mask_lower) coefs = coefs[0::2] else: coefs = solve_phase_3d(-phs_mean_lower, q1_mask_lower) print coefs theta_lower = correction_volume_3d(self.volShape, self.alpha, *coefs) theta_lower[:, n_vol_rows / 2 :, :] = theta_upper[:, n_vol_rows / 2 :, :] return theta_lower else: # for upper (u>=0), solve normal SVD coefs = solve_phase_6d(phs_mean_upper, q1_mask_upper) print coefs theta_upper = correction_volume_6d(self.volShape, self.alpha, self.beta, *coefs) # for lower (u < 0), solve with negative data coefs = solve_phase_6d(-phs_mean_lower, q1_mask_lower) print coefs theta_lower = correction_volume_6d(self.volShape, self.alpha, self.beta, *coefs) theta_lower[:, n_vol_rows / 2 :, :] = theta_upper[:, n_vol_rows / 2 :, :] return theta_lower
def run(self, image): if not verify_scanner_image(self, image): return -1 if not hasattr(image, "ref_data") or image.ref_data.shape[0] < 2: self.log("Not enough reference volumes, quitting.") return -1 self.volShape = image.shape[-3:] inv_ref0 = ifft(image.ref_data[0]) inv_ref1 = ifft(reverse(image.ref_data[1], axis=-1)) inv_ref = inv_ref0 * N.conjugate(inv_ref1) n_slice, n_pe, n_fe = self.refShape = inv_ref0.shape #phs_vol comes back shaped (n_slice, n_pe, lin2-lin1) phs_vol = unwrap_ref_volume(inv_ref) q1_mask = N.zeros((n_slice, n_pe, n_fe)) # get slice positions (in order) so we can throw out the ones # too close to the backplane of the headcoil (or not ???) if self.backplane_adj: s_idx = tag_backplane_slices(image) else: s_idx = range(n_slice) q1_mask[s_idx] = 1.0 q1_mask[s_idx, 0::2, :] = qual_map_mask(phs_vol[s_idx, 0::2, :], self.percentile) q1_mask[s_idx, 1::2, :] = qual_map_mask(phs_vol[s_idx, 1::2, :], self.percentile) theta = N.empty(self.refShape, N.float64) s_line = N.arange(n_slice) r_line = N.arange(n_fe) - n_fe / 2 B1, B2, B3 = range(3) # planar solution nrows = n_slice * n_fe M = N.zeros((nrows, 3), N.float64) M[:, B1] = N.outer(N.ones(n_slice), r_line).flatten() M[:, B2] = N.repeat(s_line, n_fe) M[:, B3] = 1. A = N.empty((n_slice, 3), N.float64) B = N.empty((3, n_fe), N.float64) A[:, 0] = 1. A[:, 1] = s_line A[:, 2] = 1. if not self.fitmeans: for m in range(n_pe): P = N.reshape(0.5 * phs_vol[:, m, :], (nrows, )) pt_mask = N.reshape(q1_mask[:, m, :], (nrows, )) nz = pt_mask.nonzero()[0] Msub = M[nz] P = P[nz] [u, sv, vt] = N.linalg.svd(Msub, full_matrices=0) coefs = N.dot(vt.transpose(), N.dot(N.diag(1 / sv), N.dot(u.transpose(), P))) B[0, :] = coefs[B1] * r_line B[1, :] = coefs[B2] B[2, :] = coefs[B3] theta[:, m, :] = N.dot(A, B) else: for rows in ('evn', 'odd'): if rows is 'evn': slicing = (slice(None), slice(0, n_pe, 2), slice(None)) else: slicing = (slice(None), slice(1, n_pe, 2), slice(None)) P = N.reshape(0.5 * phs_vol[slicing].mean(axis=-2), (nrows, )) pt_mask = q1_mask[slicing].prod(axis=-2) pt_mask.shape = (nrows, ) nz = pt_mask.nonzero()[0] Msub = M[nz] P = P[nz] [u, sv, vt] = N.linalg.svd(Msub, full_matrices=0) coefs = N.dot(vt.transpose(), N.dot(N.diag(1 / sv), N.dot(u.transpose(), P))) B[0, :] = coefs[B1] * r_line B[1, :] = coefs[B2] B[2, :] = coefs[B3] theta[slicing] = N.dot(A, B)[:, None, :] phase = N.exp(-1.j * theta).astype(image[:].dtype) from recon.tools import Recon if Recon._FAST_ARRAY: apply_phase_correction(image[:], phase) else: for dvol in image: apply_phase_correction(dvol[:], phase)
def run(self, image): if not verify_scanner_image(self, image): return -1 if not hasattr(image, "ref_data") or image.ref_data.shape[0] < 2: self.log("Not enough reference volumes, quitting.") return -1 self.volShape = image.shape[-3:] inv_ref0 = ifft(image.ref_data[0]) inv_ref1 = ifft(reverse(image.ref_data[1], axis=-1)) inv_ref = inv_ref0*N.conjugate(inv_ref1) n_slice, n_pe, n_fe = self.refShape = inv_ref0.shape #phs_vol comes back shaped (n_slice, n_pe, lin2-lin1) phs_vol = unwrap_ref_volume(inv_ref) q1_mask = N.zeros((n_slice, n_pe, n_fe)) # get slice positions (in order) so we can throw out the ones # too close to the backplane of the headcoil (or not ???) if self.backplane_adj: s_idx = tag_backplane_slices(image) else: s_idx = range(n_slice) q1_mask[s_idx] = 1.0 q1_mask[s_idx,0::2,:] = qual_map_mask(phs_vol[s_idx,0::2,:], self.percentile) q1_mask[s_idx,1::2,:] = qual_map_mask(phs_vol[s_idx,1::2,:], self.percentile) theta = N.empty(self.refShape, N.float64) s_line = N.arange(n_slice) r_line = N.arange(n_fe) - n_fe/2 B1, B2, B3 = range(3) # planar solution nrows = n_slice * n_fe M = N.zeros((nrows, 3), N.float64) M[:,B1] = N.outer(N.ones(n_slice), r_line).flatten() M[:,B2] = N.repeat(s_line, n_fe) M[:,B3] = 1. A = N.empty((n_slice, 3), N.float64) B = N.empty((3, n_fe), N.float64) A[:,0] = 1. A[:,1] = s_line A[:,2] = 1. if not self.fitmeans: for m in range(n_pe): P = N.reshape(0.5*phs_vol[:,m,:], (nrows,)) pt_mask = N.reshape(q1_mask[:,m,:], (nrows,)) nz = pt_mask.nonzero()[0] Msub = M[nz] P = P[nz] [u,sv,vt] = N.linalg.svd(Msub, full_matrices=0) coefs = N.dot(vt.transpose(), N.dot(N.diag(1/sv), N.dot(u.transpose(), P))) B[0,:] = coefs[B1]*r_line B[1,:] = coefs[B2] B[2,:] = coefs[B3] theta[:,m,:] = N.dot(A,B) else: for rows in ( 'evn', 'odd' ): if rows is 'evn': slicing = ( slice(None), slice(0, n_pe, 2), slice(None) ) else: slicing = ( slice(None), slice(1, n_pe, 2), slice(None) ) P = N.reshape(0.5*phs_vol[slicing].mean(axis=-2), (nrows,)) pt_mask = q1_mask[slicing].prod(axis=-2) pt_mask.shape = (nrows,) nz = pt_mask.nonzero()[0] Msub = M[nz] P = P[nz] [u,sv,vt] = N.linalg.svd(Msub, full_matrices=0) coefs = N.dot(vt.transpose(), N.dot(N.diag(1/sv), N.dot(u.transpose(), P))) B[0,:] = coefs[B1]*r_line B[1,:] = coefs[B2] B[2,:] = coefs[B3] theta[slicing] = N.dot(A,B)[:,None,:] phase = N.exp(-1.j*theta).astype(image[:].dtype) from recon.tools import Recon if Recon._FAST_ARRAY: apply_phase_correction(image[:], phase) else: for dvol in image: apply_phase_correction(dvol[:], phase)