def process(self, acq, data, *args): if acq.isFlagSet(ismrmrd.ACQ_IS_NOISE_MEASUREMENT): self.noise_data.append((acq, data)) else: if len(self.noise_data): profiles = len(self.noise_data) channels = self.noise_data[0][1].shape[0] samples_per_profile = self.noise_data[0][1].shape[1] noise = np.zeros((channels, profiles * samples_per_profile), dtype=np.complex64) counter = 0 for p in self.noise_data: noise[:, counter * samples_per_profile:(counter * samples_per_profile + samples_per_profile)] = p[1] counter = counter + 1 scale = (acq.sample_time_us / self.noise_data[0][0].sample_time_us) * 0.79 self.noise_dmtx = coils.calculate_prewhitening( noise, scale_factor=scale) #Test the noise adjust d = self.noise_data[0][1] d2 = coils.apply_prewhitening(d, self.noise_dmtx) self.noise_data = list() if self.noise_dmtx is not None: data2 = coils.apply_prewhitening(data, self.noise_dmtx) else: data2 = data self.put_next(acq, data2) return 0
def process(self,acq,data,*args): if acq.isFlagSet(ismrmrd.ACQ_IS_NOISE_MEASUREMENT): self.noise_data.append((acq,data)) else: if len(self.noise_data): profiles = len(self.noise_data) channels = self.noise_data[0][1].shape[0] samples_per_profile = self.noise_data[0][1].shape[1] noise = np.zeros((channels,profiles*samples_per_profile),dtype=np.complex64) counter = 0 for p in self.noise_data: noise[:,counter*samples_per_profile:(counter*samples_per_profile+samples_per_profile)] = p[1] counter = counter + 1 scale = (acq.sample_time_us/self.noise_data[0][0].sample_time_us)*0.79 self.noise_dmtx = coils.calculate_prewhitening(noise,scale_factor=scale) #Test the noise adjust d = self.noise_data[0][1] d2 = coils.apply_prewhitening(d, self.noise_dmtx) self.noise_data = list() if self.noise_dmtx is not None: data2 = coils.apply_prewhitening(data, self.noise_dmtx) else: data2 = data self.put_next(acq,data2) return 0
def reconstruct_gre(filename, datasetname, noise): # Handle the imaging data dset = ismrmrd.Dataset(filename, datasetname) header = ismrmrd.xsd.CreateFromDocument(dset.read_xml_header()) enc = header.encoding[0] # Matrix size eNx = enc.encodedSpace.matrixSize.x eNy = enc.encodedSpace.matrixSize.y rNx = enc.reconSpace.matrixSize.x rNy = enc.reconSpace.matrixSize.y # Number of Slices if enc.encodingLimits.slice != None: nslices = enc.encodingLimits.slice.maximum + 1 else: nslices = 1 # Loop through the acquisitions ignoring the noise scans firstscan = 0 while True: acq = dset.read_acquisition(firstscan) if acq.isFlagSet(ismrmrd.ACQ_IS_NOISE_MEASUREMENT): firstscan += 1 else: break acq = dset.read_acquisition(firstscan) ncoils = acq.active_channels gre_bw = header.acquisitionSystemInformation.relativeReceiverNoiseBandwidth # Initialiaze a storage array for the data data = np.zeros((nslices, ncoils, eNy, eNx), dtype=np.complex64) # Loop # Prewhiten and stuff into the buffer nacq = dset.number_of_acquisitions() for scan in range(firstscan, nacq): acq = dset.read_acquisition(scan) slice = acq.idx.slice ky = acq.idx.kspace_encode_step_1 data[slice, :, ky, :] = coils.apply_prewhitening(acq.data, noise.preWMtx) # Reconstruct calibration images # 2D FFT im = transform.transform_kspace_to_image(data, [2, 3]) # [slice,coil,x,y] # Remove oversampling if needed if (eNx != rNx): x0 = (eNx - rNx) // 2 x1 = eNx - (eNx - rNx) // 2 im = im[:, :, :, x0:x1] # close the data set dset.close() return im
def reconstruct_gre(filename, datasetname, noise): # Handle the imaging data dset = ismrmrd.Dataset(filename, datasetname) header = ismrmrd.xsd.CreateFromDocument(dset.read_xml_header()) enc = header.encoding[0] # Matrix size eNx = enc.encodedSpace.matrixSize.x eNy = enc.encodedSpace.matrixSize.y rNx = enc.reconSpace.matrixSize.x rNy = enc.reconSpace.matrixSize.y # Number of Slices if enc.encodingLimits.slice != None: nslices = enc.encodingLimits.slice.maximum + 1 else: nslices = 1 # Loop through the acquisitions ignoring the noise scans firstscan = 0 while True: acq = dset.read_acquisition(firstscan) if acq.isFlagSet(ismrmrd.ACQ_IS_NOISE_MEASUREMENT): firstscan += 1 else: break acq = dset.read_acquisition(firstscan) ncoils = acq.active_channels gre_bw = header.acquisitionSystemInformation.relativeReceiverNoiseBandwidth # Initialiaze a storage array for the data data = np.zeros((nslices, ncoils, eNy, eNx), dtype=np.complex64) # Loop # Prewhiten and stuff into the buffer nacq = dset.number_of_acquisitions() for scan in range(firstscan,nacq): acq = dset.read_acquisition(scan) slice = acq.idx.slice ky = acq.idx.kspace_encode_step_1 data[slice, :, ky, :] = coils.apply_prewhitening(acq.data,noise.preWMtx) # Reconstruct calibration images # 2D FFT im = transform.transform_kspace_to_image(data, [2,3]) # [slice,coil,x,y] # Remove oversampling if needed if (eNx != rNx): x0 = (eNx - rNx)//2 x1 = eNx - (eNx - rNx)//2 im = im[:,:,:,x0:x1] # close the data set dset.close() return im
(data,pat) = simulation.sample_data(phan,csm,acc_factor,ref_lines) #%% #Add noise noise = np.random.standard_normal(data.shape) + 1j*np.random.standard_normal(data.shape) noise = (5.0/matrix_size)*noise kspace = np.logical_or(pat==1,pat==3).astype('float32')*(data + noise) data = (pat>0).astype('float32')*(data + noise) #%% #Calculate the noise prewhitening matrix dmtx = coils.calculate_prewhitening(noise) #%% # Apply prewhitening kspace = coils.apply_prewhitening(kspace, dmtx) data = coils.apply_prewhitening(data, dmtx) #%% #Reconstruct aliased images alias_img = transform.transform_kspace_to_image(kspace,dim=(1,2)) * np.sqrt(acc_factor) show.imshow(abs(alias_img)) #%% reload(sense) (unmix_sense, gmap_sense) = sense.calculate_sense_unmixing(acc_factor,csm) show.imshow(abs(gmap_sense),colorbar=True) recon_sense = np.squeeze(np.sum(alias_img * unmix_sense,0)) show.imshow(abs(recon_sense),colorbar=True)
def reconstruct_calibration(filename, datasetname, noise=None): # Handle the imaging data dset = ismrmrd.Dataset(filename, datasetname) header = ismrmrd.xsd.CreateFromDocument(dset.read_xml_header()) enc = header.encoding[0] # Matrix size eNx = enc.encodedSpace.matrixSize.x eNy = enc.encodedSpace.matrixSize.y rNx = enc.reconSpace.matrixSize.x rNy = enc.reconSpace.matrixSize.y # Number of Slices if enc.encodingLimits.slice != None: nslices = enc.encodingLimits.slice.maximum + 1 else: nslices = 1 # Loop through the acquisitions ignoring the noise scans firstscan = 0 while True: acq = dset.read_acquisition(firstscan) if acq.isFlagSet(ismrmrd.ACQ_IS_NOISE_MEASUREMENT): firstscan += 1 else: break acq = dset.read_acquisition(firstscan) ncoils = acq.active_channels gre_bw = header.acquisitionSystemInformation.relativeReceiverNoiseBandwidth # The calibration data may be have fewer points than the full k refNx = acq.number_of_samples x0 = (eNx - refNx)// 2 x1 = eNx - (eNx - refNx)//2 # Reconsparallel imaging calibration scans which are GRE based # Initialiaze a storage array for the reference data ref_data = np.zeros((nslices, ncoils, eNy, eNx), dtype=np.complex64) # Loop # Prewhiten and stuff into the buffer scan = firstscan while True: acq = dset.read_acquisition(scan) if acq.isFlagSet(ismrmrd.ACQ_IS_PARALLEL_CALIBRATION): slice = acq.idx.slice ky = acq.idx.kspace_encode_step_1 if noise: ref_data[slice, :, ky, x0:x1] = coils.apply_prewhitening(acq.data,noise.preWMtx) else: ref_data[slice, :, ky, x0:x1] = acq.data scan += 1 else: break # Reconstruct calibration images # 2D FFT im_ref = transform.transform_kspace_to_image(ref_data, [2,3]) # [slice,coil,x,y] # Remove oversampling if needed if (eNx != rNx): x0 = (eNx - rNx)//2 x1 = eNx - (eNx - rNx)//2 im_ref = im_ref[:,:,:,x0:x1] # close the data set dset.close() return im_ref
def reconstruct_epi(filename, datasetname, noise, gre): # Read the epi data dset = ismrmrd.Dataset(filename,datasetname) ############################## # Scan Parameters and Layout # ############################## header = ismrmrd.xsd.CreateFromDocument(dset.read_xml_header()) enc = header.encoding[0] nkx = enc.encodedSpace.matrixSize.x nky = enc.encodedSpace.matrixSize.y ncoils = header.acquisitionSystemInformation.receiverChannels epi_noise_bw = header.acquisitionSystemInformation.relativeReceiverNoiseBandwidth acc_factor = enc.parallelImaging.accelerationFactor.kspace_encoding_step_1 # Number of Slices if enc.encodingLimits.slice != None: nslices = enc.encodingLimits.slice.maximum + 1 else: nslices = 1 # Loop through the acquisitions ignoring the noise scans and the # parallel imaging calibration scans which are EPI based firstscan = 0 while True: acq = dset.read_acquisition(firstscan) if acq.isFlagSet(ismrmrd.ACQ_IS_NOISE_MEASUREMENT) or acq.isFlagSet(ismrmrd.ACQ_IS_PARALLEL_CALIBRATION): firstscan += 1 else: break #print('First imaging scan at:', firstscan) nsamp = acq.number_of_samples ncoils = acq.active_channels sampletime = acq.sample_time_us # The lines are labeled with flags as follows: # - Noise or Imaging using ACQ_IS_NOISE_MEASUREMENT # - Parallel calibration using ACQ_IS_PARALLEL_CALIBRATION # - Forward or Reverse using the ACQ_IS_REVERSE flag # - EPI navigator using ACQ_IS_PHASECORR_DATA # - First or last in a slice using ACQ_FIRST_IN_SLICE and ACQ_LAST_IN_SLICE # - The first navigator in a shot is labeled as first in slice # - The first imaging line in a shot is labeled as firt in slice # - The last imaging line in a show is labeled as last in slice # for n in range(firstscan-1,firstscan+60): # acq = dset.read_acquisition(n) # print(acq.idx.kspace_encode_step_1) # if acq.isFlagSet(ismrmrd.ACQ_FIRST_IN_SLICE): # print('First') # elif acq.isFlagSet(ismrmrd.ACQ_LAST_IN_SLICE): # print('Last') # else: # print('Middle') # if acq.isFlagSet(ismrmrd.ACQ_IS_REVERSE): # print('Reverse') # else: # print('Forward') # if acq.isFlagSet(ismrmrd.ACQ_IS_PHASECORR_DATA): # print('Navigator') # The EPI trajectory is described in the XML header # for o in enc.trajectoryDescription.userParameterLong: # print(o.name, o.value_) # # for o in enc.trajectoryDescription.userParameterDouble: # print(o.name, o.value_) tup = tdown = tflat = tdelay = nsamp = nnav = etl = 0 for o in enc.trajectoryDescription.userParameterLong: if o.name == 'rampUpTime': tup = o.value_ if o.name == 'rampDownTime': tdown = o.value_ if o.name == 'flatTopTime': tflat = o.value_ if o.name == 'acqDelayTime': tdelay = o.value_ if o.name == 'numSamples': nsamp = o.value_ if o.name == 'numberOfNavigators': nnav = o.value_ if o.name == 'etl': etl = o.value_ #print(tup, tdown, tflat, tdelay, nsamp, nnav, etl) #################################### # Calculate the gridding operators # #################################### nkx = enc.encodedSpace.matrixSize.x nx = enc.reconSpace.matrixSize.x t = tdelay + sampletime*np.arange(nsamp) x = np.arange(nx)/nx-0.5 up = t<=tup flat = (t>tup)*(t<(tup+tflat)) down = t>=(tup+tflat) #Integral of trajectory (Gmax=1.0) k = np.zeros(nsamp) k[up] = 0.5/tup*t[up]**2 k[flat] = 0.5*tup + (t[flat] - tup) k[down] = 0.5*tup + tflat + 0.5*tdown-0.5/tdown*(tup+tflat+tdown-t[down])**2 #Scale to match resolution k *= nkx/(k[-1]-k[0]) #Center k -= k[nsamp//2] kpos = k kneg = -1.0*k #Corresponding even range keven = np.arange(nkx) keven -= keven[nkx//2] #Forward model Qpos = np.zeros([nsamp,nkx]) Qneg = np.zeros([nsamp,nkx]) for p in range(nsamp): Qpos[p,:] = np.sinc(kpos[p]-keven) Qneg[p,:] = np.sinc(kneg[p]-keven) #Inverse Rpos = np.linalg.pinv(Qpos) Rneg = np.linalg.pinv(Qneg) #Take transpose because we apply from the right Rpos = Rpos.transpose() Rneg = Rneg.transpose() ################################# # Calculate the kspace filter # # Hanning filter after gridding # ################################# import scipy.signal kfiltx = scipy.signal.hann(nkx) kfilty = scipy.signal.hann(nky) Rpos = np.dot(Rpos, np.diag(kfiltx)) Rneg = np.dot(Rneg, np.diag(kfiltx)) #################################### # Calculate SENSE unmixing weights # #################################### # Some basic checks if gre.shape[0] != nslices: raise ValueError('Calibration and EPI data have different number of slices') if gre.shape[1] != ncoils: raise ValueError('Calibration and EPI data have different number of coils') # Estimate coil sensitivites from the GRE data csm_orig = np.zeros(gre.shape,dtype=np.complex) for z in range(nslices): (csmtmp, actmp, rhotmp) = coils.calculate_csm_inati_iter(gre[z,:,:,:]) weight = rhotmp**2 / (rhotmp**2 + .01*np.median(rhotmp.ravel())**2) csm_orig[z,:,:,:] = csmtmp*weight # Deal with difference in resolution # Up/down sample the coil sensitivities to the resolution of the EPI xcsm = np.arange(gre.shape[3])/gre.shape[3] ycsm = np.arange(gre.shape[2])/gre.shape[2] xepi = np.arange(nx)/nx yepi = np.arange(nky)/nky csm = np.zeros([nslices,ncoils,nky,nx],dtype=np.complex) for z in range(nslices): for c in range(ncoils): # interpolate the real part and imaginary part separately i_real = interp.RectBivariateSpline(ycsm,xcsm,np.real(csm_orig[z,c,:,:])) i_imag = interp.RectBivariateSpline(ycsm,xcsm,np.imag(csm_orig[z,c,:,:])) csm[z,c,:,:] = i_real(yepi,xepi) + 1j*i_imag(yepi,xepi) # SENSE weights unmix = np.zeros(csm.shape,dtype=np.complex) for z in range(nslices): unmix[z,:,:,:] = sense.calculate_sense_unmixing(acc_factor, csm[z,:,:,:])[0] ############### # Reconstruct # ############### # Initialize the array for a volume's worth of data H = np.zeros([nslices, ncoils, nky, nx],dtype=np.complex) # Loop over the slices scan = firstscan for z in range(nslices): #print('Slice %d starts at scan %d.'%(z,scan)) # Navigator 1 acq = dset.read_acquisition(scan) #print(scan,acq.idx.slice,acq.idx.kspace_encode_step_1,acq.isFlagSet(ismrmrd.ACQ_IS_REVERSE)) currslice = acq.idx.slice # keep track of the slice number data = coils.apply_prewhitening(acq.data,noise.preWMtx) if acq.isFlagSet(ismrmrd.ACQ_IS_REVERSE): rnav1 = transform.transform_kspace_to_image(np.dot(data, Rneg),dim=[1]) sgn = -1.0 else: rnav1 = transform.transform_kspace_to_image(np.dot(data, Rpos),dim=[1]) sgn = 1.0 scan += 1 # Navigator 2 acq = dset.read_acquisition(scan) #print(scan,acq.idx.slice,acq.idx.kspace_encode_step_1,acq.isFlagSet(ismrmrd.ACQ_IS_REVERSE)) data = coils.apply_prewhitening(acq.data,noise.preWMtx) if acq.isFlagSet(ismrmrd.ACQ_IS_REVERSE): rnav2 = transform.transform_kspace_to_image(np.dot(data, Rneg),dim=[1]) else: rnav2 = transform.transform_kspace_to_image(np.dot(data, Rpos),dim=[1]) scan += 1 # Navigator 3 acq = dset.read_acquisition(scan) #print(scan,acq.idx.slice,acq.idx.kspace_encode_step_1,acq.isFlagSet(ismrmrd.ACQ_IS_REVERSE)) data = coils.apply_prewhitening(acq.data,noise.preWMtx) if acq.isFlagSet(ismrmrd.ACQ_IS_REVERSE): rnav3 = transform.transform_kspace_to_image(np.dot(data, Rneg),dim=[1]) else: rnav3 = transform.transform_kspace_to_image(np.dot(data, Rpos),dim=[1]) scan += 1 # Phase correction delta = np.conj(rnav1+rnav3) * rnav2 fdelta = np.tile(np.mean(delta,axis=0),[ncoils,1]) corr = np.exp(sgn*1j*np.angle(np.sqrt(fdelta))) for j in range(nky): acq = dset.read_acquisition(scan) slice = acq.idx.slice if slice != currslice: # end of this slice break ky = acq.idx.kspace_encode_step_1 data = coils.apply_prewhitening(acq.data,noise.preWMtx) if acq.isFlagSet(ismrmrd.ACQ_IS_REVERSE): rho = transform.transform_kspace_to_image(np.dot(data, Rneg),dim=[1]) H[slice,:,ky,:] = kfilty[ky]*np.conj(corr)*rho else: rho = transform.transform_kspace_to_image(np.dot(data, Rpos),dim=[1]) H[slice,:,ky,:] = kfilty[ky]*corr*rho scan += 1 # Close the data set dset.close() # Recon in along y H = transform.transform_kspace_to_image(H,dim=[2]) # Combine with SENSE weights epi_im = np.abs(np.squeeze(np.sum(H*unmix,axis=1))) return epi_im
def reconstruct_calibration(filename, datasetname, noise=None): # Handle the imaging data dset = ismrmrd.Dataset(filename, datasetname) header = ismrmrd.xsd.CreateFromDocument(dset.read_xml_header()) enc = header.encoding[0] # Matrix size eNx = enc.encodedSpace.matrixSize.x eNy = enc.encodedSpace.matrixSize.y rNx = enc.reconSpace.matrixSize.x rNy = enc.reconSpace.matrixSize.y # Number of Slices if enc.encodingLimits.slice != None: nslices = enc.encodingLimits.slice.maximum + 1 else: nslices = 1 # Loop through the acquisitions ignoring the noise scans firstscan = 0 while True: acq = dset.read_acquisition(firstscan) if acq.isFlagSet(ismrmrd.ACQ_IS_NOISE_MEASUREMENT): firstscan += 1 else: break acq = dset.read_acquisition(firstscan) ncoils = acq.active_channels gre_bw = header.acquisitionSystemInformation.relativeReceiverNoiseBandwidth # The calibration data may be have fewer points than the full k refNx = acq.number_of_samples x0 = (eNx - refNx) // 2 x1 = eNx - (eNx - refNx) // 2 # Reconsparallel imaging calibration scans which are GRE based # Initialiaze a storage array for the reference data ref_data = np.zeros((nslices, ncoils, eNy, eNx), dtype=np.complex64) # Loop # Prewhiten and stuff into the buffer scan = firstscan while True: acq = dset.read_acquisition(scan) if acq.isFlagSet(ismrmrd.ACQ_IS_PARALLEL_CALIBRATION): slice = acq.idx.slice ky = acq.idx.kspace_encode_step_1 if noise: ref_data[slice, :, ky, x0:x1] = coils.apply_prewhitening( acq.data, noise.preWMtx) else: ref_data[slice, :, ky, x0:x1] = acq.data scan += 1 else: break # Reconstruct calibration images # 2D FFT im_ref = transform.transform_kspace_to_image(ref_data, [2, 3]) # [slice,coil,x,y] # Remove oversampling if needed if (eNx != rNx): x0 = (eNx - rNx) // 2 x1 = eNx - (eNx - rNx) // 2 im_ref = im_ref[:, :, :, x0:x1] # close the data set dset.close() return im_ref
def reconstruct_epi(filename, datasetname, noise, gre): # Read the epi data dset = ismrmrd.Dataset(filename, datasetname) ############################## # Scan Parameters and Layout # ############################## header = ismrmrd.xsd.CreateFromDocument(dset.read_xml_header()) enc = header.encoding[0] nkx = enc.encodedSpace.matrixSize.x nky = enc.encodedSpace.matrixSize.y ncoils = header.acquisitionSystemInformation.receiverChannels epi_noise_bw = header.acquisitionSystemInformation.relativeReceiverNoiseBandwidth acc_factor = enc.parallelImaging.accelerationFactor.kspace_encoding_step_1 # Number of Slices if enc.encodingLimits.slice != None: nslices = enc.encodingLimits.slice.maximum + 1 else: nslices = 1 # Loop through the acquisitions ignoring the noise scans and the # parallel imaging calibration scans which are EPI based firstscan = 0 while True: acq = dset.read_acquisition(firstscan) if acq.isFlagSet(ismrmrd.ACQ_IS_NOISE_MEASUREMENT) or acq.isFlagSet( ismrmrd.ACQ_IS_PARALLEL_CALIBRATION): firstscan += 1 else: break #print('First imaging scan at:', firstscan) nsamp = acq.number_of_samples ncoils = acq.active_channels sampletime = acq.sample_time_us # The lines are labeled with flags as follows: # - Noise or Imaging using ACQ_IS_NOISE_MEASUREMENT # - Parallel calibration using ACQ_IS_PARALLEL_CALIBRATION # - Forward or Reverse using the ACQ_IS_REVERSE flag # - EPI navigator using ACQ_IS_PHASECORR_DATA # - First or last in a slice using ACQ_FIRST_IN_SLICE and ACQ_LAST_IN_SLICE # - The first navigator in a shot is labeled as first in slice # - The first imaging line in a shot is labeled as firt in slice # - The last imaging line in a show is labeled as last in slice # for n in range(firstscan-1,firstscan+60): # acq = dset.read_acquisition(n) # print(acq.idx.kspace_encode_step_1) # if acq.isFlagSet(ismrmrd.ACQ_FIRST_IN_SLICE): # print('First') # elif acq.isFlagSet(ismrmrd.ACQ_LAST_IN_SLICE): # print('Last') # else: # print('Middle') # if acq.isFlagSet(ismrmrd.ACQ_IS_REVERSE): # print('Reverse') # else: # print('Forward') # if acq.isFlagSet(ismrmrd.ACQ_IS_PHASECORR_DATA): # print('Navigator') # The EPI trajectory is described in the XML header # for o in enc.trajectoryDescription.userParameterLong: # print(o.name, o.value_) # # for o in enc.trajectoryDescription.userParameterDouble: # print(o.name, o.value_) tup = tdown = tflat = tdelay = nsamp = nnav = etl = 0 for o in enc.trajectoryDescription.userParameterLong: if o.name == 'rampUpTime': tup = o.value_ if o.name == 'rampDownTime': tdown = o.value_ if o.name == 'flatTopTime': tflat = o.value_ if o.name == 'acqDelayTime': tdelay = o.value_ if o.name == 'numSamples': nsamp = o.value_ if o.name == 'numberOfNavigators': nnav = o.value_ if o.name == 'etl': etl = o.value_ #print(tup, tdown, tflat, tdelay, nsamp, nnav, etl) #################################### # Calculate the gridding operators # #################################### nkx = enc.encodedSpace.matrixSize.x nx = enc.reconSpace.matrixSize.x t = tdelay + sampletime * np.arange(nsamp) x = np.arange(nx) / nx - 0.5 up = t <= tup flat = (t > tup) * (t < (tup + tflat)) down = t >= (tup + tflat) #Integral of trajectory (Gmax=1.0) k = np.zeros(nsamp) k[up] = 0.5 / tup * t[up]**2 k[flat] = 0.5 * tup + (t[flat] - tup) k[down] = 0.5 * tup + tflat + 0.5 * tdown - 0.5 / tdown * ( tup + tflat + tdown - t[down])**2 #Scale to match resolution k *= nkx / (k[-1] - k[0]) #Center k -= k[nsamp // 2] kpos = k kneg = -1.0 * k #Corresponding even range keven = np.arange(nkx) keven -= keven[nkx // 2] #Forward model Qpos = np.zeros([nsamp, nkx]) Qneg = np.zeros([nsamp, nkx]) for p in range(nsamp): Qpos[p, :] = np.sinc(kpos[p] - keven) Qneg[p, :] = np.sinc(kneg[p] - keven) #Inverse Rpos = np.linalg.pinv(Qpos) Rneg = np.linalg.pinv(Qneg) #Take transpose because we apply from the right Rpos = Rpos.transpose() Rneg = Rneg.transpose() ################################# # Calculate the kspace filter # # Hanning filter after gridding # ################################# import scipy.signal kfiltx = scipy.signal.hann(nkx) kfilty = scipy.signal.hann(nky) Rpos = np.dot(Rpos, np.diag(kfiltx)) Rneg = np.dot(Rneg, np.diag(kfiltx)) #################################### # Calculate SENSE unmixing weights # #################################### # Some basic checks if gre.shape[0] != nslices: raise ValueError( 'Calibration and EPI data have different number of slices') if gre.shape[1] != ncoils: raise ValueError( 'Calibration and EPI data have different number of coils') # Estimate coil sensitivites from the GRE data csm_orig = np.zeros(gre.shape, dtype=np.complex) for z in range(nslices): (csmtmp, actmp, rhotmp) = coils.calculate_csm_inati_iter(gre[z, :, :, :]) weight = rhotmp**2 / (rhotmp**2 + .01 * np.median(rhotmp.ravel())**2) csm_orig[z, :, :, :] = csmtmp * weight # Deal with difference in resolution # Up/down sample the coil sensitivities to the resolution of the EPI xcsm = np.arange(gre.shape[3]) / gre.shape[3] ycsm = np.arange(gre.shape[2]) / gre.shape[2] xepi = np.arange(nx) / nx yepi = np.arange(nky) / nky csm = np.zeros([nslices, ncoils, nky, nx], dtype=np.complex) for z in range(nslices): for c in range(ncoils): # interpolate the real part and imaginary part separately i_real = interp.RectBivariateSpline(ycsm, xcsm, np.real(csm_orig[z, c, :, :])) i_imag = interp.RectBivariateSpline(ycsm, xcsm, np.imag(csm_orig[z, c, :, :])) csm[z, c, :, :] = i_real(yepi, xepi) + 1j * i_imag(yepi, xepi) # SENSE weights unmix = np.zeros(csm.shape, dtype=np.complex) for z in range(nslices): unmix[z, :, :, :] = sense.calculate_sense_unmixing( acc_factor, csm[z, :, :, :])[0] ############### # Reconstruct # ############### # Initialize the array for a volume's worth of data H = np.zeros([nslices, ncoils, nky, nx], dtype=np.complex) # Loop over the slices scan = firstscan for z in range(nslices): #print('Slice %d starts at scan %d.'%(z,scan)) # Navigator 1 acq = dset.read_acquisition(scan) #print(scan,acq.idx.slice,acq.idx.kspace_encode_step_1,acq.isFlagSet(ismrmrd.ACQ_IS_REVERSE)) currslice = acq.idx.slice # keep track of the slice number data = coils.apply_prewhitening(acq.data, noise.preWMtx) if acq.isFlagSet(ismrmrd.ACQ_IS_REVERSE): rnav1 = transform.transform_kspace_to_image(np.dot(data, Rneg), dim=[1]) sgn = -1.0 else: rnav1 = transform.transform_kspace_to_image(np.dot(data, Rpos), dim=[1]) sgn = 1.0 scan += 1 # Navigator 2 acq = dset.read_acquisition(scan) #print(scan,acq.idx.slice,acq.idx.kspace_encode_step_1,acq.isFlagSet(ismrmrd.ACQ_IS_REVERSE)) data = coils.apply_prewhitening(acq.data, noise.preWMtx) if acq.isFlagSet(ismrmrd.ACQ_IS_REVERSE): rnav2 = transform.transform_kspace_to_image(np.dot(data, Rneg), dim=[1]) else: rnav2 = transform.transform_kspace_to_image(np.dot(data, Rpos), dim=[1]) scan += 1 # Navigator 3 acq = dset.read_acquisition(scan) #print(scan,acq.idx.slice,acq.idx.kspace_encode_step_1,acq.isFlagSet(ismrmrd.ACQ_IS_REVERSE)) data = coils.apply_prewhitening(acq.data, noise.preWMtx) if acq.isFlagSet(ismrmrd.ACQ_IS_REVERSE): rnav3 = transform.transform_kspace_to_image(np.dot(data, Rneg), dim=[1]) else: rnav3 = transform.transform_kspace_to_image(np.dot(data, Rpos), dim=[1]) scan += 1 # Phase correction delta = np.conj(rnav1 + rnav3) * rnav2 fdelta = np.tile(np.mean(delta, axis=0), [ncoils, 1]) corr = np.exp(sgn * 1j * np.angle(np.sqrt(fdelta))) for j in range(nky): acq = dset.read_acquisition(scan) slice = acq.idx.slice if slice != currslice: # end of this slice break ky = acq.idx.kspace_encode_step_1 data = coils.apply_prewhitening(acq.data, noise.preWMtx) if acq.isFlagSet(ismrmrd.ACQ_IS_REVERSE): rho = transform.transform_kspace_to_image(np.dot(data, Rneg), dim=[1]) H[slice, :, ky, :] = kfilty[ky] * np.conj(corr) * rho else: rho = transform.transform_kspace_to_image(np.dot(data, Rpos), dim=[1]) H[slice, :, ky, :] = kfilty[ky] * corr * rho scan += 1 # Close the data set dset.close() # Recon in along y H = transform.transform_kspace_to_image(H, dim=[2]) # Combine with SENSE weights epi_im = np.abs(np.squeeze(np.sum(H * unmix, axis=1))) return epi_im
def compute(self): do_squeeze = self.getVal('Squeeze') do_remos = self.getVal('Remove Oversampling') do_zeropad = self.getVal('Zeropad') do_noiseadj = self.getVal('Noise Adjust') receiver_noise_bw = self.getVal('Receiver Noise BW Ratio') #Get the file name use the file browser widget fname = gpi.TranslateFileURI(self.getVal('File Browser')) #Check if the file exists if not os.path.exists(fname): self.log.node("Path does not exist: "+str(fname)) return 0 dset = ismrmrd.Dataset(fname, 'dataset', create_if_needed=False) xml_header = dset.read_xml_header() header = ismrmrd.xsd.CreateFromDocument(xml_header) self.setData('ISMRMRDHeader', str(xml_header)) enc = header.encoding[0] # Matrix size eNx = enc.encodedSpace.matrixSize.x eNy = enc.encodedSpace.matrixSize.y eNz = enc.encodedSpace.matrixSize.z rNx = enc.reconSpace.matrixSize.x rNy = enc.reconSpace.matrixSize.y rNz = enc.reconSpace.matrixSize.z # Field of View eFOVx = enc.encodedSpace.fieldOfView_mm.x eFOVy = enc.encodedSpace.fieldOfView_mm.y eFOVz = enc.encodedSpace.fieldOfView_mm.z rFOVx = enc.reconSpace.fieldOfView_mm.x rFOVy = enc.reconSpace.fieldOfView_mm.y rFOVz = enc.reconSpace.fieldOfView_mm.z # Number of Slices, Reps, Contrasts, etc. ncoils = header.acquisitionSystemInformation.receiverChannels if enc.encodingLimits.slice != None: nslices = enc.encodingLimits.slice.maximum + 1 else: nslices = 1 if enc.encodingLimits.repetition != None: nreps = enc.encodingLimits.repetition.maximum + 1 else: nreps = 1 if enc.encodingLimits.contrast != None: ncontrasts = enc.encodingLimits.contrast.maximum + 1 else: ncontrasts = 1 # In case there are noise scans in the actual dataset, we will skip them. noise_data = list() noise_dmtx = None firstacq=0 for acqnum in range(dset.number_of_acquisitions()): acq = dset.read_acquisition(acqnum) if acq.isFlagSet(ismrmrd.ACQ_IS_NOISE_MEASUREMENT): noise_data.append((acq.getHead(),acq.data)) continue else: firstacq = acqnum break if len(noise_data): profiles = len(noise_data) channels = noise_data[0][1].shape[0] samples_per_profile = noise_data[0][1].shape[1] noise = np.zeros((channels,profiles*samples_per_profile),dtype=np.complex64) counter = 0 for p in noise_data: noise[:,counter*samples_per_profile:(counter*samples_per_profile+samples_per_profile)] = p[1] counter = counter + 1 self.setData('noise',noise) scale = (acq.sample_time_us/noise_data[0][0].sample_time_us)*receiver_noise_bw noise_dmtx = coils.calculate_prewhitening(noise,scale_factor=scale) noise_data = list() # Empty array for the output data acq = dset.read_acquisition(firstacq) ro_length = acq.number_of_samples padded_ro_length = (acq.number_of_samples-acq.center_sample)*2 size_nx = 0 if do_remos: size_nx = rNx do_zeropad = True elif do_zeropad: size_nx = padded_ro_length else: size_nx = ro_length all_data = np.zeros((nreps, ncontrasts, nslices, ncoils, eNz, eNy, size_nx), dtype=np.complex64) # Loop through the rest of the acquisitions and stuff for acqnum in range(firstacq,dset.number_of_acquisitions()): acq = dset.read_acquisition(acqnum) acq_data_prw = np.zeros(acq.data.shape,dtype=np.complex64) acq_data_prw[:] = acq.data[:] if do_noiseadj and (noise_dmtx is not None): acq_data_prw = coils.apply_prewhitening(acq_data_prw, noise_dmtx) data2 = None if (padded_ro_length != ro_length) and do_zeropad: #partial fourier data2 = np.zeros((acq_data_prw.shape[0], padded_ro_length),dtype=np.complex64) offset = (padded_ro_length>>1) - acq.center_sample data2[:,0+offset:offset+ro_length] = acq_data_prw else: data2 = acq_data_prw if do_remos: data2=transform.transform_kspace_to_image(data2,dim=(1,)) data2=data2[:,(padded_ro_length>>2):(padded_ro_length>>2)+(padded_ro_length>>1)] data2=transform.transform_image_to_kspace(data2,dim=(1,)) * np.sqrt(float(padded_ro_length)/ro_length) # Stuff into the buffer rep = acq.idx.repetition contrast = acq.idx.contrast slice = acq.idx.slice y = acq.idx.kspace_encode_step_1 z = acq.idx.kspace_encode_step_2 all_data[rep, contrast, slice, :, z, y, :] = data2 all_data = all_data.astype('complex64') if do_squeeze: all_data = np.squeeze(all_data) self.setData('data',all_data) return 0
noise_receiver_bw_ratio = 0.79 dmtx = coils.calculate_prewhitening( noise, scale_factor=(data_dwell_time / noise_dwell_time) * noise_receiver_bw_ratio) #%% # Process the actual data all_data = np.zeros((nreps, ncontrasts, nslices, ncoils, eNz, eNy, rNx), dtype=np.complex64) # Loop through the rest of the acquisitions and stuff for acqnum in range(firstacq, dset.number_of_acquisitions()): acq = dset.read_acquisition(acqnum) acq_data_prw = coils.apply_prewhitening(acq.data, dmtx) # Remove oversampling if needed if eNx != rNx: xline = transform.transform_kspace_to_image(acq_data_prw, [1]) x0 = (eNx - rNx) / 2 x1 = (eNx - rNx) / 2 + rNx xline = xline[:, x0:x1] acq.resize(rNx, acq.active_channels, acq.trajectory_dimensions) acq.center_sample = rNx / 2 # need to use the [:] notation here to fill the data acq.data[:] = transform.transform_image_to_kspace(xline, [1]) # Stuff into the buffer rep = acq.idx.repetition contrast = acq.idx.contrast
(data, pat) = simulation.sample_data(phan, csm, acc_factor, ref_lines) #%% # Add noise noise = np.random.standard_normal(data.shape) + 1j * np.random.standard_normal(data.shape) noise = (5.0 / matrix_size) * noise kspace = np.logical_or(pat == 1, pat == 3).astype("float32") * (data + noise) data = (pat > 0).astype("float32") * (data + noise) #%% # Calculate the noise prewhitening matrix dmtx = coils.calculate_prewhitening(noise) #%% # Apply prewhitening kspace = coils.apply_prewhitening(kspace, dmtx) data = coils.apply_prewhitening(data, dmtx) #%% # Reconstruct aliased images alias_img = transform.transform_kspace_to_image(kspace, dim=(1, 2)) * np.sqrt(acc_factor) show.imshow(abs(alias_img)) #%% reload(sense) (unmix_sense, gmap_sense) = sense.calculate_sense_unmixing(acc_factor, csm) show.imshow(abs(gmap_sense), colorbar=True) recon_sense = np.squeeze(np.sum(alias_img * unmix_sense, 0)) show.imshow(abs(recon_sense), colorbar=True)
#Calculate prewhiterner taking BWs into consideration a = dset.read_acquisition(firstacq) data_dwell_time = a.sample_time_us noise_receiver_bw_ratio = 0.79 dmtx = coils.calculate_prewhitening(noise,scale_factor=(data_dwell_time/noise_dwell_time)*noise_receiver_bw_ratio) #%% # Process the actual data all_data = np.zeros((nreps, ncontrasts, nslices, ncoils, eNz, eNy, rNx), dtype=np.complex64) # Loop through the rest of the acquisitions and stuff for acqnum in range(firstacq,dset.number_of_acquisitions()): acq = dset.read_acquisition(acqnum) acq_data_prw = coils.apply_prewhitening(acq.data,dmtx) # Remove oversampling if needed if eNx != rNx: xline = transform.transform_kspace_to_image(acq_data_prw, [1]) x0 = (eNx - rNx) / 2 x1 = (eNx - rNx) / 2 + rNx xline = xline[:,x0:x1] acq.resize(rNx,acq.active_channels,acq.trajectory_dimensions) acq.center_sample = rNx/2 # need to use the [:] notation here to fill the data acq.data[:] = transform.transform_image_to_kspace(xline, [1]) # Stuff into the buffer rep = acq.idx.repetition contrast = acq.idx.contrast