def run(self, image): "Correct for Nyquist ghosting due to field inhomogeneity." if not verify_scanner_image(self, image): return if not self.fmap_file: self.log("No field map file provided, quitting") return if not image.isepi: self.log("Can't apply inhomogeneity correction"\ " to non-epi sequences, quitting") return fMap = readImage(self.fmap_file) # grab the fieldmap, ignore the mask fMap = fMap.subImage(0) if fMap.shape[-3:] != image.shape[-3:]: self.log("This field map's shape does not match"\ " the image shape, quitting") return shift = (image.idim * image.T_pe/2/N.pi) #watch the sign pixel_pos = -shift*fMap[:] + N.outer(N.arange(fMap.jdim), N.ones(fMap.jdim)) image[:].real = resample_phase_axis(abs(image[:]), pixel_pos) image[:].imag = 0.
def run(self, image): # basic tasks here: # 1: data preparation # 2: phase unwrapping # 3: find mean phase diff lines (2 means or 4, depending on sequence) # 4: solve for linear coefficients # 5: create correction matrix from coefs # 6: apply correction to all image volumes # # * all linearly-sampled data can be treated in a generalized way by # paying attention to the interleave factor (self.xleave) and # the sampling trajectory+timing of each row (image.epi_trajectory) # # * centric sampled data, whose k-space trajectory had opposite # directions, needs special treatment: basically the general case # is handled in separated parts if not verify_scanner_image(self, image): return -1 if not hasattr(image, "ref_data"): self.log("No reference volume, quitting") return -1 if len(image.ref_data.shape) > 3 and image.ref_data.shape[-4] > 1: self.log("Could be performing Balanced Phase Correction!") self.volShape = image.shape[-3:] refVol = image.ref_data[0] n_slice, n_ref_rows, n_fe = self.refShape = refVol.shape # iscentric says whether kspace is multishot centric; # xleave is the factor to which kspace data has been interleaved # (in the case of multishot interleave) iscentric = image.sampstyle is "centric" self.xleave = iscentric and 1 or image.nseg self.alpha, self.beta, _, self.ref_alpha = image.epi_trajectory() # get slice positions (in order) so we can throw out the ones # too close to the backplane of the headcoil # self.good_slices = tag_backplane_slices(image) self.good_slices = range(n_slice) # want to fork the code based on sampling style if iscentric: theta = self.run_centric(image) else: theta = self.run_linear(image) phase = N.exp(-1.0j * theta).astype(image[:].dtype) from recon.tools import Recon ## apply_phase_correction(image[:], phase) # this is faster?? if Recon._FAST_ARRAY: apply_phase_correction(image[:], phase) else: for dvol in image: apply_phase_correction(dvol[:], phase)
def run(self, image): # basic tasks here: # 1: data preparation # 2: phase unwrapping # 3: find mean phase diff lines (2 means or 4, depending on sequence) # 4: solve for linear coefficients # 5: create correction matrix from coefs # 6: apply correction to all image volumes # # * all linearly-sampled data can be treated in a generalized way by # paying attention to the interleave factor (self.xleave) and # the sampling trajectory+timing of each row (image.epi_trajectory) # # * centric sampled data, whose k-space trajectory had opposite # directions, needs special treatment: basically the general case # is handled in separated parts if not verify_scanner_image(self, image): return -1 if not hasattr(image, "ref_data"): self.log("No reference volume, quitting") return -1 if len(image.ref_data.shape) > 3 and image.ref_data.shape[-4] > 1: self.log("Could be performing Balanced Phase Correction!") self.volShape = image.shape[-3:] refVol = image.ref_data[0] n_slice, n_ref_rows, n_fe = self.refShape = refVol.shape # iscentric says whether kspace is multishot centric; # xleave is the factor to which kspace data has been interleaved # (in the case of multishot interleave) iscentric = image.sampstyle is "centric" self.xleave = iscentric and 1 or image.nseg self.alpha, self.beta, _, self.ref_alpha = image.epi_trajectory() # get slice positions (in order) so we can throw out the ones # too close to the backplane of the headcoil #self.good_slices = tag_backplane_slices(image) self.good_slices = range(n_slice) # want to fork the code based on sampling style if iscentric: theta = self.run_centric(image) else: theta = self.run_linear(image) phase = N.exp(-1.j * theta).astype(image[:].dtype) from recon.tools import Recon ## apply_phase_correction(image[:], phase) # this is faster?? 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 fmap_file = clean_name(self.fmap_file)[0] ## if hasattr(image, 'n_chan'): ## fmap_file += '.c%02d'%image.chan try: fmapIm = readImage(fmap_file) except: self.log("fieldmap not found: " + fmap_file) return -1 (nslice, npe, nfe) = image.shape[-3:] # make sure that the length of the q1 columns of the fmap # are AT LEAST equal to that of the image regrid_fac = max(npe, fmapIm.shape[-2]) # fmap and chi-mask are swapped to be of shape (Q1,Q2) fmap = np.swapaxes( regrid_bilinear(fmapIm[0], regrid_fac, axis=-2).astype(np.float64), -1, -2) chi = np.swapaxes(regrid_bilinear(fmapIm[1], regrid_fac, axis=-2), -1, -2) Q1, Q2 = fmap.shape[-2:] # compute T_n2 vector Tl = image.T_pe delT = image.delT a, b, n2, _ = image.epi_trajectory() K = get_kernel(Q2, Tl, b, n2, fmap, chi) for s in range(nslice): # dchunk is shaped (nvol, npe, nfe) # inverse transform along nfe (can't do in-place) dchunk = ifft1(image[:, s, :, :]) # now shape is (nfe, npe, nvol) dchunk = np.swapaxes(dchunk, 0, 2) for fe in range(nfe): # want to solve Kx = y for x # K is (npe,npe), and y is (npe,nvol) # # There seems to be a trade-off here as nvol changes... # Doing this in two steps is faster for large nvol; I think # it takes advantage of the faster BLAS matrix-product in dot # as opposed to LAPACK's linear solver. For smaller values # of nvol, the overhead seems to outweigh the benefit. iK = regularized_inverse(K[s, fe], self.lmbda) dchunk[fe] = np.dot(iK, dchunk[fe]) dchunk = np.swapaxes(dchunk, 0, 2) # fft x back to kx, can do inplace here fft1(dchunk, inplace=True) image[:, s, :, :] = dchunk
def run(self, image): if not verify_scanner_image(self, image): return fmap_file = clean_name(self.fmap_file)[0] ## if hasattr(image, 'n_chan'): ## fmap_file += '.c%02d'%image.chan try: fmapIm = readImage(fmap_file) except: self.log("fieldmap not found: " + fmap_file) return -1 (nslice, npe, nfe) = image.shape[-3:] # make sure that the length of the q1 columns of the fmap # are AT LEAST equal to that of the image regrid_fac = max(npe, fmapIm.shape[-2]) # fmap and chi-mask are swapped to be of shape (Q1,Q2) fmap = np.swapaxes(regrid_bilinear(fmapIm[0], regrid_fac, axis=-2).astype(np.float64), -1, -2) chi = np.swapaxes(regrid_bilinear(fmapIm[1], regrid_fac, axis=-2), -1, -2) Q1, Q2 = fmap.shape[-2:] # compute T_n2 vector Tl = image.T_pe delT = image.delT a, b, n2, _ = image.epi_trajectory() K = get_kernel(Q2, Tl, b, n2, fmap, chi) for s in range(nslice): # dchunk is shaped (nvol, npe, nfe) # inverse transform along nfe (can't do in-place) dchunk = ifft1(image[:, s, :, :]) # now shape is (nfe, npe, nvol) dchunk = np.swapaxes(dchunk, 0, 2) for fe in range(nfe): # want to solve Kx = y for x # K is (npe,npe), and y is (npe,nvol) # # There seems to be a trade-off here as nvol changes... # Doing this in two steps is faster for large nvol; I think # it takes advantage of the faster BLAS matrix-product in dot # as opposed to LAPACK's linear solver. For smaller values # of nvol, the overhead seems to outweigh the benefit. iK = regularized_inverse(K[s, fe], self.lmbda) dchunk[fe] = np.dot(iK, dchunk[fe]) dchunk = np.swapaxes(dchunk, 0, 2) # fft x back to kx, can do inplace here fft1(dchunk, inplace=True) image[:, s, :, :] = dchunk
def run(self, image): if not verify_scanner_image(self, image): return acq_order = image.acq_order data = image[:, :, :, :] change_slices_inplace(data, acq_order) if hasattr(image, 'ref_data'): data = image.ref_data[:, :, :, :] change_slices_inplace(data, acq_order) if hasattr(image, 'acs_data') and image.acs_data is not None: data = image.acs_data[:, :, :, :] change_slices_inplace(data, acq_order) if hasattr(image, 'acs_ref_data') and image.acs_ref_data is not None: data = image.acs_ref_data[:, :, :, :] change_slices_inplace(data, acq_order)
def run(self, image): if not verify_scanner_image(self, image): return acq_order = image.acq_order data = image[:,:,:,:] change_slices_inplace(data, acq_order) if hasattr(image, 'ref_data'): data = image.ref_data[:,:,:,:] change_slices_inplace(data, acq_order) if hasattr(image, 'acs_data') and image.acs_data is not None: data = image.acs_data[:,:,:,:] change_slices_inplace(data, acq_order) if hasattr(image, 'acs_ref_data') and image.acs_ref_data is not None: data = image.acs_ref_data[:,:,:,:] change_slices_inplace(data, acq_order)
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)