def compute(self): all_data = self.getData('data') xml_header = self.getData('ISMRMRDHeader') header = ismrmrd.xsd.CreateFromDocument(xml_header) enc = header.encoding[0] #Parallel imaging factor acc_factor = 1 if enc.parallelImaging: acc_factor = enc.parallelImaging.accelerationFactor.kspace_encoding_step_1 # Coil combination print "Calculating coil images and CSM" coil_images = transform.transform_kspace_to_image(np.squeeze(np.mean(all_data,0)),(1,2)) (csm,rho) = coils.calculate_csm_walsh(coil_images) csm_ss = np.sum(csm * np.conj(csm),0) csm_ss = csm_ss + 1.0*(csm_ss < np.spacing(1)).astype('float32') if acc_factor > 1: coil_data = np.squeeze(np.mean(all_data,0)) if self.getVal('Parallel Imaging Method') == 0: (unmix,gmap) = grappa.calculate_grappa_unmixing(coil_data, acc_factor,csm=csm) elif self.getVal('Parallel Imaging Method') == 1: (unmix,gmap) = sense.calculate_sense_unmixing(acc_factor,csm) else: raise Exception('Unknown parallel imaging method') recon = np.zeros((all_data.shape[-4],all_data.shape[-2],all_data.shape[-1]), dtype=np.complex64) for r in range(0,all_data.shape[-4]): recon_data = transform.transform_kspace_to_image(np.squeeze(all_data[r,:,:,:]),(1,2))*np.sqrt(acc_factor) if acc_factor > 1: recon[r,:,:] = np.sum(unmix * recon_data,0) else: recon[r,:,:] = np.sum(np.conj(csm) * recon_data,0) print "Reconstruction done" self.setData('recon', recon) if acc_factor == 1: gmap = np.ones((all_data.shape[-2],all_data.shape[-1]),dtype=np.float32) self.setData('gmap',gmap) return 0
def process(self, recondata, *args): print np.shape(recondata[0].data.data) image = transform.transform_kspace_to_image(recondata[0].data.data, dim=(0, 1, 2)) image = np.reshape( image, (image.shape[0], image.shape[1], image.shape[2], image.shape[3])) #Create a new image header and transfer value acq = np.ravel(recondata[0].data.headers)[0] img_head = ismrmrd.ImageHeader() img_head.channels = acq.active_channels img_head.slice = acq.idx.slice img_head.matrix_size = (image.shape[0], image.shape[1], image.shape[2]) img_head.position = acq.position img_head.read_dir = acq.read_dir img_head.phase_dir = acq.phase_dir img_head.slice_dir = acq.slice_dir img_head.patient_table_position = acq.patient_table_position img_head.acquisition_time_stamp = acq.acquisition_time_stamp img_head.image_index = 0 img_head.image_series_index = 0 img_head.data_type = ismrmrd.DATATYPE_CXFLOAT #Return image to Gadgetron self.put_next(img_head, image) print "Slice ", img_head.slice return 0
def process(self, recondata,*args): print np.shape(recondata[0].data.data) image = transform.transform_kspace_to_image(recondata[0].data.data,dim=(0,1,2)) image = np.reshape(image,(image.shape[0],image.shape[1],image.shape[2],image.shape[3])) #Create a new image header and transfer value acq = np.ravel(recondata[0].data.headers)[0] img_head = ismrmrd.ImageHeader() img_head.channels = acq.active_channels img_head.slice = acq.idx.slice img_head.matrix_size = (image.shape[0],image.shape[1],image.shape[2]) img_head.position = acq.position img_head.read_dir = acq.read_dir img_head.phase_dir = acq.phase_dir img_head.slice_dir = acq.slice_dir img_head.patient_table_position = acq.patient_table_position img_head.acquisition_time_stamp = acq.acquisition_time_stamp img_head.image_index = 0 img_head.image_series_index = 0 img_head.data_type = ismrmrd.DATATYPE_CXFLOAT #Return image to Gadgetron self.put_next(img_head,image) print "Slice ", img_head.slice 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
def process(self, acq, data): orig_size = list(data.shape); data2 = data.reshape([(data.size/data.shape[data.ndim-1]), data.shape[data.ndim-1]]) new_length = data2.shape[1]>>1 data2 = transform.transform_image_to_kspace(transform.transform_kspace_to_image(data2,dim=(1,))[:,(0+(new_length>>1)):(new_length+(new_length>>1))],dim=(1,)) orig_size[data.ndim-1] = new_length data2.reshape(tuple(orig_size)) acq.samples = new_length self.put_next(acq,data2) return 0
def process(self, acq, data, *args): if self.myBuffer is None: channels = acq.active_channels if self.enc.encodingLimits.slice != None: nslices = self.enc.encodingLimits.slice.maximum + 1 else: nslices = 1 eNz = self.enc.encodedSpace.matrixSize.z eNy = self.enc.encodedSpace.matrixSize.y eNx = self.enc.encodedSpace.matrixSize.x self.myBuffer = np.zeros( (int(eNx / 2), eNy, eNz, nslices, channels), dtype=np.complex64) line_offset = self.enc.encodedSpace.matrixSize.y / 2 - self.enc.encodingLimits.kspace_encoding_step_1.center self.myBuffer[:, int(acq.idx.kspace_encode_step_1 + line_offset), int(acq.idx.kspace_encode_step_2), int(acq.idx.slice), :] = data if (acq.flags & (1 << 7)): #Is this the last scan in slice image = transform.transform_kspace_to_image(self.myBuffer, dim=(0, 1, 2)) image = image * np.product( image.shape) * 100 #Scaling for the scanner #Create a new image header and transfer value img_head = ismrmrd.ImageHeader() img_head.channels = acq.active_channels img_head.slice = acq.idx.slice img_head.matrix_size[0] = self.myBuffer.shape[0] img_head.matrix_size[1] = self.myBuffer.shape[1] img_head.matrix_size[2] = self.myBuffer.shape[2] img_head.position = acq.position img_head.read_dir = acq.read_dir img_head.phase_dir = acq.phase_dir img_head.slice_dir = acq.slice_dir img_head.patient_table_position = acq.patient_table_position img_head.acquisition_time_stamp = acq.acquisition_time_stamp img_head.image_index = self.myCounter img_head.image_series_index = self.mySeries img_head.data_type = ismrmrd.DATATYPE_CXFLOAT self.myCounter += 1 if self.myCounter > 5: self.mySeries += 1 self.myCounter = 1 #Return image to Gadgetron self.put_next(img_head, image.astype('complex64'), *args) #print "Returning to Gadgetron" return 0 #Everything OK
def read_kspace_from_ocmr_data(file_path='./ocmr_data/us_0143_pt_1_5T.h5'): import numpy as np import matplotlib.pyplot as plt import math from ismrmrdtools import show, transform import read_ocmr as read # Load the data, display size of kData and scan parmaters kData, param = read.read_ocmr(file_path); print('Dimension of kData: ', kData.shape) print('Scan paramters:') import pprint; pprint.pprint(param) # Show the sampling Pattern # kData_tmp-[kx,ky,kz,coil,phase,set,slice,rep], samp-[kx,ky,kz,phase,set,slice,rep] dim_kData = kData.shape; CH = dim_kData[3]; SLC = dim_kData[6]; kData_tmp = np.mean(kData, axis=8); # average the k-space if average > 1 samp = (abs(np.mean(kData_tmp, axis=3)) > 0).astype(np.int) # kx ky kz phase set slice slc_idx = math.floor(SLC / 2); fig1 = plt.figure(1); fig1.suptitle("Sampling Pattern", fontsize=14); plt.subplot2grid((1, 8), (0, 0), colspan=6); tmp = plt.imshow(np.transpose(np.squeeze(samp[:, :, 0, 0, 0, slc_idx])), aspect='auto'); plt.xlabel('kx'); plt.ylabel('ky'); tmp.set_clim(0.0, 1.0) # ky by kx plt.subplot2grid((1, 9), (0, 7), colspan=2); tmp = plt.imshow(np.squeeze(samp[int(dim_kData[0] / 2), :, 0, :, 0, slc_idx]), aspect='auto'); plt.xlabel('frame'); plt.yticks([]); tmp.set_clim(0.0, 1.0) # ky by frame # Average the k-sapce along phase(time) dimension kData_sl = kData_tmp[:, :, :, :, :, :, slc_idx, 0]; samp_avg = np.repeat(np.sum(samp[:, :, :, :, :, slc_idx, 0], 3), CH, axis=3) + np.finfo(float).eps kData_sl_avg = np.divide(np.squeeze(np.sum(kData_sl, 4)), np.squeeze(samp_avg)); im_avg = transform.transform_kspace_to_image(kData_sl_avg, [0, 1]); # IFFT (2D image) im = np.sqrt(np.sum(np.abs(im_avg) ** 2, 2)) # Sum of Square fig2 = plt.figure(2); plt.imshow(np.transpose(im), cmap='gray'); plt.axis('off'); # Show the image plt.show()
def process(self, acq, data): orig_size = list(data.shape) data2 = data.reshape([data.shape[0], int(data.size / data.shape[0])]) new_length = data2.shape[0] >> 1 data2 = transform.transform_image_to_kspace( transform.transform_kspace_to_image( data2, dim=(0, ))[(0 + (new_length >> 1)):(new_length + (new_length >> 1)), :], dim=(0, )) orig_size[0] = new_length data2.reshape(tuple(orig_size)) acq.samples = new_length self.put_next(acq, data2) return 0
def process(self, acq, data,*args): if self.myBuffer is None: channels = acq.active_channels if self.enc.encodingLimits.slice != None: nslices = self.enc.encodingLimits.slice.maximum + 1 else: nslices = 1 eNz = self.enc.encodedSpace.matrixSize.z eNy = self.enc.encodedSpace.matrixSize.y eNx = self.enc.encodedSpace.matrixSize.x self.myBuffer = np.zeros(( int(eNx/2),eNy,eNz,nslices,channels),dtype=np.complex64) line_offset = self.enc.encodedSpace.matrixSize.y/2 - self.enc.encodingLimits.kspace_encoding_step_1.center self.myBuffer[:,int(acq.idx.kspace_encode_step_1+line_offset), int(acq.idx.kspace_encode_step_2), int(acq.idx.slice),:] = data if (acq.flags & (1<<7)): #Is this the last scan in slice image = transform.transform_kspace_to_image(self.myBuffer,dim=(0,1,2)) image = image * np.product(image.shape)*100 #Scaling for the scanner #Create a new image header and transfer value img_head = ismrmrd.ImageHeader() img_head.channels = acq.active_channels img_head.slice = acq.idx.slice img_head.matrix_size[0] = self.myBuffer.shape[0] img_head.matrix_size[1] = self.myBuffer.shape[1] img_head.matrix_size[2] = self.myBuffer.shape[2] img_head.position = acq.position img_head.read_dir = acq.read_dir img_head.phase_dir = acq.phase_dir img_head.slice_dir = acq.slice_dir img_head.patient_table_position = acq.patient_table_position img_head.acquisition_time_stamp = acq.acquisition_time_stamp img_head.image_index = self.myCounter img_head.image_series_index = self.mySeries img_head.data_type = ismrmrd.DATATYPE_CXFLOAT self.myCounter += 1 if self.myCounter > 5: self.mySeries += 1 self.myCounter = 1 #Return image to Gadgetron self.put_next(img_head,image.astype('complex64'),*args) #print "Returning to Gadgetron" return 0 #Everything OK
def process(self, acq, data,*args): if not acq.isFlagSet(ismrmrd.ACQ_IS_NOISE_MEASUREMENT): ro_length = acq.number_of_samples padded_ro_length = (acq.number_of_samples-acq.center_sample)*2 if padded_ro_length != ro_length: #partial fourier data2 = np.zeros((data.shape[0], padded_ro_length),dtype=np.complex64) offset = (padded_ro_length>>1) - acq.center_sample data2[:,0+offset:offset+ro_length] = data else: data2 = data 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) acq.center_sample = padded_ro_length>>2 acq.number_of_samples = data2.shape[1] self.put_next(acq,data2,*args) return 0
def sortspokes(all_data, nframes, spf): print "sorting spokes" datasqueeze = all_data.squeeze() datasqueeze = datasqueeze.transpose(3, 2, 1, 0) # entangle slab encoding datasqueeze = transform.transform_kspace_to_image(datasqueeze, [2]) datasqueeze = datasqueeze.transpose(0, 1, 3, 2) data_ = np.zeros((2 * eNx, spf, ncoils, nparts, nframes), dtype=np.complex64) print "nframes=", nframes for j in range(nframes): data_[:, :, :, :, j] = datasqueeze[:, j * spf:(j + 1) * spf, :, :] data_ = data_.transpose(0, 1, 2, 4, 3) print " ... done" return data_
def process(self, recondata): print(np.shape(recondata[0].data.data)) image = transform.transform_kspace_to_image(recondata[0].data.data,dim=(0,1,2)) print(np.shape(image)) #image = np.reshape(image,(image.shape[0],image.shape[1],image.shape[2],image.shape[3])) #Create a new image header and transfer value print(type(recondata[0].data.headers)) print(np.shape(recondata[0].data.headers)) acq = np.ravel(recondata[0].data.headers)[0] print(type(acq)) print(acq.active_channels) print(acq.idx.slice) dims=np.shape(recondata[0].data.data) print(dims) for s in range(dims[6]): img_head = ismrmrd.ImageHeader() img_head.channels = acq.active_channels img_head.slice = s #acq.idx.slice img_head.matrix_size = (image.shape[0],image.shape[1],image.shape[2]) img_head.position = acq.position img_head.read_dir = acq.read_dir img_head.phase_dir = acq.phase_dir img_head.slice_dir = acq.slice_dir img_head.patient_table_position = acq.patient_table_position img_head.acquisition_time_stamp = acq.acquisition_time_stamp img_head.image_index = 0 img_head.image_series_index = 0 img_head.data_type = ismrmrd.DATATYPE_CXFLOAT #Return image to Gadgetron print(np.shape(image[:,:,:,:,0,0,s])) self.put_next(img_head,image[:,:,:,:,:,:,s]) print("Slice ", img_head.slice) print("----------------------------------------------") return 0
def SimpleBufferedDataPythonGadget(connection): logging.info("Python reconstruction running - reading readout data") start = time.time() counter=0 for acquisition in connection: #acquisition is a vector of structure called reconBit #print(type(acquisition[0])) for reconBit in acquisition: print(type(reconBit)) # reconBit.ref is the calibration for parallel imaging # reconBit.data is the undersampled dataset print('-----------------------') # each of them include a specific header and the kspace data print(type(reconBit.data.headers)) print(type(reconBit.data.data)) print(reconBit.data.headers.shape) print(reconBit.data.data.shape) # use get_first_index_of_non_empty_header() instead of 34 repetition=reconBit.data.headers.flat[34].idx.repetition print(repetition) # 2D ifft im = transform.transform_kspace_to_image(reconBit.data.data, [0,1]) plt.subplot(121) plt.imshow(np.abs(np.squeeze(reconBit.data.data[:,:,0,0,0,0,0]))) plt.subplot(122) plt.imshow(np.abs(np.squeeze(im[:,:,0,0,0,0,0]))) plt.show() connection.send(acquisition) logging.info(f"Python reconstruction done. Duration: {(time.time() - start):.2f} s")
def reconstruct_fully_sampled_ocmr_datasets(filename='./ocmr_data/fs_0005_1_5T.h5'): import numpy as np import matplotlib.pyplot as plt import math from ismrmrdtools import show, transform # import ReadWrapper import read_ocmr as read # Load the data, display size of kData and scan parmaters kData, param = read.read_ocmr(filename); print('Dimension of kData: ', kData.shape) # Image reconstruction (SoS) dim_kData = kData.shape; CH = dim_kData[3]; SLC = dim_kData[6]; kData_tmp = np.mean(kData, axis=8); # average the k-space if average > 1 im_coil = transform.transform_kspace_to_image(kData_tmp, [0, 1]); # IFFT (2D image) im_sos = np.sqrt(np.sum(np.abs(im_coil) ** 2, 3)); # Sum of Square print('Dimension of Image (with ReadOut ovesampling): ', im_sos.shape) RO = im_sos.shape[0]; image = im_sos[math.floor(RO / 4):math.floor(RO / 4 * 3), :, :]; # Remove RO oversampling print('Dimension of Image (without ReadOout ovesampling): ', image.shape) # Show the reconstructed cine image from IPython.display import clear_output import time slc_idx = math.floor(SLC / 2); print(slc_idx) image_slc = np.squeeze(image[:, :, :, :, :, :, slc_idx]); for rep in range(5): # repeate the movie for 5 times for frame in range(image_slc.shape[2]): clear_output(wait=True) plt.imshow(image_slc[:, :, frame], cmap='gray'); plt.axis('off'); plt.show() time.sleep(0.03)
def process(self, recondata): # receive kspace data and # extract acq_data and acq_header array_acq_headers = recondata[0].data.headers kspace_data = recondata[0].data.data try: if recondata[0].ref.data is not None: print("reference data exist") print( np.shape(recondata[0].ref.data) ) # only for repetition 0 # il faut creer le bucket recon grappa reference = recondata[0].ref.data data = recondata[0].data.data print(np.shape(reference)) print(np.shape(data)) self.array_calib = reference np.save('/tmp/gadgetron/reference', reference) np.save('/tmp/gadgetron/data', data) except: print("reference data not exist") # grappa array_data = recondata[0].data.data dims = np.shape(recondata[0].data.data) kspace_data_tmp = np.ndarray(dims, dtype=np.complex64) for slc in range(0, dims[6]): for n in range(0, dims[5]): for s in range(0, dims[4]): kspace = array_data[:, :, :, :, s, n, slc] calib = self.array_calib[:, :, :, :, s, n, slc] calib = np.squeeze(calib, axis=2) kspace = np.squeeze(kspace, axis=2) sx, sy, ncoils = kspace.shape[:] cx, cy, ncoils = calib.shape[:] # Here's the actual reconstruction res = grappa(kspace, calib, kernel_size=(5, 5), coil_axis=-1) # Here's the resulting shape of the reconstruction. The coil # axis will end up in the same place you provided it in sx, sy, ncoils = res.shape[:] kspace_data_tmp[:, :, 0, :, s, n, slc] = res # ifft, this is necessary for the next gadget #image = transform.transform_kspace_to_image(kspace_data_tmp,dim=(0,1,2)) image = transform.transform_kspace_to_image(kspace_data_tmp, dim=(0, 1, 2)) # create a new IsmrmrdImageArray array_data = IsmrmrdImageArray() # attache the images to the IsmrmrdImageArray array_data.data = image # get dimension for the acq_headers dims_header = np.shape(recondata[0].data.headers) # get one header with typical info acq = np.ravel(array_acq_headers)[0] print("acq.idx.repetition", acq.idx.repetition) if (acq.idx.repetition == 0): np.save('/tmp/gadgetron/image', image) headers_list = [] base_header = ismrmrd.ImageHeader() base_header.version = 2 ndims_image = np.shape(image) base_header.channels = ndims_image[3] base_header.matrix_size = (image.shape[0], image.shape[1], image.shape[2]) print((image.shape[0], image.shape[1], image.shape[2])) base_header.position = acq.position base_header.read_dir = acq.read_dir base_header.phase_dir = acq.phase_dir base_header.slice_dir = acq.slice_dir base_header.patient_table_position = acq.patient_table_position base_header.acquisition_time_stamp = acq.acquisition_time_stamp base_header.image_index = 0 base_header.image_series_index = 0 base_header.data_type = ismrmrd.DATATYPE_CXFLOAT base_header.image_type = ismrmrd.IMTYPE_MAGNITUDE print("ready to list") for slc in range(0, dims_header[4]): for n in range(0, dims_header[3]): for s in range(0, dims_header[2]): #for e2 in range(0, dims_header[1]): # for e1 in range(0, dims_header[0]): headers_list.append(base_header) array_headers_test = np.array(headers_list, dtype=np.dtype(object)) print(type(array_headers_test)) print(np.shape(array_headers_test)) array_headers_test = np.reshape( array_headers_test, (dims_header[2], dims_header[3], dims_header[4])) print(type(array_headers_test)) print(np.shape(array_headers_test)) print("---> ok 0") # how to copy acquisition header into image header in python ? for slc in range(0, dims_header[4]): for n in range(0, dims_header[3]): for s in range(0, dims_header[2]): # for e2 in range(0, dims_header[1]): # for e1 in range(0, dims_header[0]): array_headers_test[s, n, slc].slice = slc #print(s,n,slc) #print(type(array_headers_test[s,n,slc])) #print(array_headers_test[s,n,slc].slice) #print("---> ok 1") # print(np.shape(array_image_header)) # attache the image headers to the IsmrmrdImageArray array_data.headers = array_headers_test #print("---> ok 2") # Return image to Gadgetron #print(np.shape(array_data.data)) #print(np.shape(array_data.headers)) #print(type(array_data.data)) #print(type(array_data.headers)) #print(type(array_data)) # send the data to the next gadget for slc in range(0, dims_header[4]): for n in range(0, dims_header[3]): for s in range(0, dims_header[2]): #print("send out image %d-%d-%d" % (s, n, slc)) a = array_data.data[:, :, :, :, s, n, slc] #array_data.headers[s,n,slc].slice=slc #print(a.shape, array_data.headers[s,n,slc].slice) self.put_next(array_data.headers[s, n, slc], a) #self.put_next( [IsmrmrdReconBit(array_data.headers, array_data.data)] , ) print("----------------------------------------------") return 0
def load_ismrmrd_ifft3d_reconstruction(filename): """ Load .h5 file, read header (head) and reconstruct images Parameters ---------- filename : path to the .h5 file Returns ------- head : read imsrmrd dataset head (dataset.head) hdr : deserialized ismrmrd xml dataset file img_scaled : reconstructed image """ if not os.path.isfile(filename): print("%s is not a valid file" % filename) raise SystemExit dset = ismrmrd.Dataset(filename, 'dataset', create_if_needed=False) #Read some fields from the XML header hdr = ismrmrd.xsd.CreateFromDocument(dset.read_xml_header()) #get encoding and reconstruction information enc = hdr.encoding[0] # Matrix size eNx = enc.encodedSpace.matrixSize.x eNy = enc.encodedSpace.matrixSize.y eNz = enc.encodedSpace.matrixSize.z rNx = enc.reconSpace.matrixSize.x # Number of Slices, Reps, Contrasts, etc. #We have to wrap the following in a if/else because a valid xml header may #not have an entry for some of the parameters ncoils = hdr.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 # Loop through the acquisitions looking for noise scans firstacq = 0 for acqnum in range(dset.number_of_acquisitions()): acq = dset.read_acquisition(acqnum) # TODO: Currently ignoring noise scans if acq.isFlagSet(ismrmrd.ACQ_IS_NOISE_MEASUREMENT): print("Found noise scan at acq ", acqnum) continue else: firstacq = acqnum print("Imaging acquisition starts acq ", acqnum) break # Initialiaze a storage array 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) head = acq.getHead() # TODO: this is where we would apply noise pre-whitening #padd if acquisition data is not complete (padding) if acq.data.shape[1] < eNx: x0 = int((eNx - acq.data.shape[1]) / 2) zeros = np.zeros((acq.data.shape[0], x0)) padded_acq_data = np.append(np.append(zeros, acq.data, axis=1), zeros, axis=1) acq.resize(eNx, acq.active_channels, acq.trajectory_dimensions) acq.data[:] = padded_acq_data # Remove oversampling if needed if eNx != rNx: #xline = transform.transform_kspace_to_image(acq.data, [1]) xline = transform.transform_kspace_to_image(acq.data, dim=(1, ), img_shape=(eNx, )) x0 = int((eNx - rNx) / 2) x1 = int((eNx - rNx) / 2 + rNx) xline = xline[:, x0:x1] acq.resize(rNx, acq.active_channels, acq.trajectory_dimensions) acq.center_sample = int(rNx / 2) # need to use the [:] notation here to fill the data acq.data[:] = transform.transform_image_to_kspace(xline, dim=(1, ), k_shape=(rNx, )) # 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, :] = acq.data # Reconstruct images images = np.zeros((nreps, ncontrasts, nslices, eNz, eNy, rNx), dtype=np.float32) img_scaled = [] for rep in range(nreps): for contrast in range(ncontrasts): for slice in range(nslices): # FFT if eNz > 1: # 3D im = transform.transform_kspace_to_image( all_data[rep, contrast, slice, :, :, :, :], [1, 2, 3]) else: # 2D im = transform.transform_kspace_to_image( all_data[rep, contrast, slice, :, 0, :, :], [2, 3]) # Sum of squares im = np.sqrt(np.sum(np.abs(im)**2, 0)) # Stuff into the output if eNz > 1: # 3D images[rep, contrast, slice, :, :, :] = im else: # 2D images[rep, contrast, slice, 0, :, :] = im img_scaled.append(im) dset.close() return [head, hdr, img_scaled]
fig1.suptitle("Sampling Pattern", fontsize=14) plt.subplot2grid((1, 8), (0, 0), colspan=6) tmp = plt.imshow(np.transpose(np.squeeze(samp[:, :, 0, 0, 0, slc_idx])), aspect='auto') plt.xlabel('kx') plt.ylabel('ky') tmp.set_clim(0.0, 1.0) # ky by kx plt.subplot2grid((1, 9), (0, 7), colspan=2) tmp = plt.imshow(np.squeeze(samp[int(dim_kData[0] / 2), :, 0, :, 0, slc_idx]), aspect='auto') plt.xlabel('frame') plt.yticks([]) tmp.set_clim(0.0, 1.0) # ky by frame plt.show() # %% Display the time averaged image # Average the k-sapce along phase(time) dimension kData_sl = kData_tmp[:, :, :, :, :, :, slc_idx, 0] samp_avg = np.repeat(np.sum(samp[:, :, :, :, :, slc_idx, 0], 3), CH, axis=3) + np.finfo(float).eps kData_sl_avg = np.divide(np.squeeze(np.sum(kData_sl, 4)), np.squeeze(samp_avg)) im_avg = transform.transform_kspace_to_image(kData_sl_avg, [0, 1]) # IFFT (2D image) im = np.sqrt(np.sum(np.abs(im_avg)**2, 2)) # Sum of Square fig2 = plt.figure(1) plt.imshow(np.transpose(im), vmin=0, vmax=0.8 * np.amax(im), cmap='gray') plt.axis('off') # Show the image plt.show()
def PyGrappaBufferedDataPythonGadget(connection): logging.info("Python reconstruction running - reading readout data") start = time.time() counter=0 reference=[] for acquisition in connection: #acquisition is a vector of structure called reconBit print(type(acquisition[0])) for reconBit in acquisition: print(type(reconBit)) # reconBit.ref is the calibration for parallel imaging # reconBit.data is the undersampled dataset print('-----------------------') # each of them include a specific header and the kspace data print(type(reconBit.data.headers)) print(type(reconBit.data.data)) print(reconBit.data.headers.shape) print(reconBit.data.data.shape) index= get_first_index_of_non_empty_header(reconBit.data.headers.flat) repetition=reconBit.data.headers.flat[index].idx.repetition print(repetition) reference_header=reconBit.data.headers.flat[0] try: if reconBit.ref.data is not None: print("reference data exist") np.save('/tmp/gadgetron/reference', reconBit.ref.data) reference=reconBit.ref.data else: print("reference data not exist") except: print("issue with reference data") dims=reconBit.data.data.shape kspace_data_tmp=np.zeros(dims, reconBit.data.data.dtype) for slc in range(0, dims[6]): for n in range(0, dims[5]): for s in range(0, dims[4]): kspace=reconBit.data.data[:,:,:,:,s,n,slc] calib=reference[:,:,:,:,s,n,slc] calib=np.squeeze(calib,axis=2) kspace=np.squeeze(kspace,axis=2) sx, sy, ncoils = kspace.shape[:] cx, cy, ncoils = calib.shape[:] # Here's the actual reconstruction res = grappa(kspace, calib, kernel_size=(5, 5), coil_axis=-1) # Here's the resulting shape of the reconstruction. The coil # axis will end up in the same place you provided it in sx, sy, ncoils = res.shape[:] kspace_data_tmp[:,:,0,:,s,n,slc]=res # ifft, this is necessary for the next gadget #image = transform.transform_kspace_to_image(kspace_data_tmp,dim=(0,1,2)) im = transform.transform_kspace_to_image(kspace_data_tmp,dim=(0,1,2)) plt.subplot(121) plt.imshow(np.abs(np.squeeze(reconBit.data.data[:,:,0,0,0,0,0]))) plt.subplot(122) plt.imshow(np.abs(np.squeeze(im[:,:,0,0,0,0,0]))) plt.show() send_reconstructed_images(connection,im,reference_header) #connection.send(acquisition) logging.info(f"Python reconstruction done. Duration: {(time.time() - start):.2f} s")
def process(self, acq, data,*args): if self.buffer is None: # Matrix size eNx = self.enc.encodedSpace.matrixSize.x eNy = self.enc.encodedSpace.matrixSize.y eNz = self.enc.encodedSpace.matrixSize.z rNx = self.enc.reconSpace.matrixSize.x rNy = self.enc.reconSpace.matrixSize.y rNz = self.enc.reconSpace.matrixSize.z # Field of View eFOVx = self.enc.encodedSpace.fieldOfView_mm.x eFOVy = self.enc.encodedSpace.fieldOfView_mm.y eFOVz = self.enc.encodedSpace.fieldOfView_mm.z rFOVx = self.enc.reconSpace.fieldOfView_mm.x rFOVy = self.enc.reconSpace.fieldOfView_mm.y rFOVz = self.enc.reconSpace.fieldOfView_mm.z channels = acq.active_channels if data.shape[1] != rNx: raise("Error, Recon gadget expects data to be on correct matrix size in RO direction") if (rNz != 1): rasie("Error Recon Gadget only supports 2D for now") self.buffer = np.zeros((channels, rNy, rNx),dtype=np.complex64) self.samp_mask = np.zeros(self.buffer.shape[1:]) self.header_proto = ismrmrd.ImageHeader() self.header_proto.matrix_size[0] = rNx self.header_proto.matrix_size[1] = rNy self.header_proto.matrix_size[2] = rNz self.header_proto.field_of_view[0] = rFOVx self.header_proto.field_of_view[1] = rFOVy self.header_proto.field_of_view[0] = rFOVz #Now put data in buffer line_offset = self.buffer.shape[1]/2 - self.enc.encodingLimits.kspace_encoding_step_1.center self.buffer[:,acq.idx.kspace_encode_step_1+line_offset,:] = data self.samp_mask[acq.idx.kspace_encode_step_1+line_offset,:] = 1 #If last scan in buffer, do FFT and fill image header if acq.isFlagSet(ismrmrd.ACQ_LAST_IN_ENCODE_STEP1) or acq.isFlagSet(ismrmrd.ACQ_LAST_IN_SLICE): img_head = copy.deepcopy(self.header_proto) img_head.position = acq.position img_head.read_dir = acq.read_dir img_head.phase_dir = acq.phase_dir img_head.slice_dir = acq.slice_dir img_head.patient_table_position = acq.patient_table_position img_head.acquisition_time_stamp = acq.acquisition_time_stamp img_head.slice = acq.idx.slice img_head.channels = 1 scale = self.samp_mask.size/(1.0*np.sum(self.samp_mask[:])); #We have not yet calculated unmixing coefficients if self.unmix is None: self.calib_buffer.append((img_head,self.buffer.copy())) self.buffer[:] = 0 self.samp_mask[:] = 0 if len(self.calib_buffer) >= self.calib_frames: cal_data = np.zeros(self.calib_buffer[0][1].shape, dtype=np.complex64) for c in self.calib_buffer: cal_data = cal_data + c[1] mask = np.squeeze(np.sum(np.abs(cal_data),0)) mask = np.ones(mask.shape)*(np.abs(mask)>0.0) target = None #cal_data[0:8,:,:] coil_images = transform.transform_kspace_to_image(cal_data,dim=(1,2)) (csm,rho) = coils.calculate_csm_walsh(coil_images) if self.method == 'grappa': self.unmix, self.gmap = grappa.calculate_grappa_unmixing(cal_data, self.acc_factor, data_mask=mask, kernel_size=(4,5), csm=csm) elif self.method == 'sense': self.unmix, self.gmap = sense.calculate_sense_unmixing(self.acc_factor, csm) else: raise Exception('Unknown parallel imaging method: ' + str(self.method)) for c in self.calib_buffer: recon = transform.transform_kspace_to_image(c[1],dim=(1,2))*np.sqrt(scale) recon = np.squeeze(np.sum(recon * self.unmix,0)) self.put_next(c[0], recon,*args) return 0 if self.unmix is None: raise Exception("We should never reach this point without unmixing coefficients") recon = transform.transform_kspace_to_image(self.buffer,dim=(1,2))*np.sqrt(scale) recon = np.squeeze(np.sum(recon * self.unmix,0)) self.buffer[:] = 0 self.samp_mask[:] = 0 self.put_next(img_head,recon,*args) return 0
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) #%% # 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 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, :] = acq.data
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 process(self, acq, data, *args): if self.buffer is None: # Matrix size eNx = self.enc.encodedSpace.matrixSize.x eNy = self.enc.encodedSpace.matrixSize.y eNz = self.enc.encodedSpace.matrixSize.z rNx = self.enc.reconSpace.matrixSize.x rNy = self.enc.reconSpace.matrixSize.y rNz = self.enc.reconSpace.matrixSize.z # Field of View eFOVx = self.enc.encodedSpace.fieldOfView_mm.x eFOVy = self.enc.encodedSpace.fieldOfView_mm.y eFOVz = self.enc.encodedSpace.fieldOfView_mm.z rFOVx = self.enc.reconSpace.fieldOfView_mm.x rFOVy = self.enc.reconSpace.fieldOfView_mm.y rFOVz = self.enc.reconSpace.fieldOfView_mm.z channels = acq.active_channels if data.shape[1] != rNx: raise ( "Error, Recon gadget expects data to be on correct matrix size in RO direction" ) if (rNz != 1): rasie("Error Recon Gadget only supports 2D for now") self.buffer = np.zeros((channels, rNy, rNx), dtype=np.complex64) self.samp_mask = np.zeros(self.buffer.shape[1:]) self.header_proto = ismrmrd.ImageHeader() self.header_proto.matrix_size[0] = rNx self.header_proto.matrix_size[1] = rNy self.header_proto.matrix_size[2] = rNz self.header_proto.field_of_view[0] = rFOVx self.header_proto.field_of_view[1] = rFOVy self.header_proto.field_of_view[0] = rFOVz #Now put data in buffer line_offset = self.buffer.shape[ 1] / 2 - self.enc.encodingLimits.kspace_encoding_step_1.center self.buffer[:, acq.idx.kspace_encode_step_1 + line_offset, :] = data self.samp_mask[acq.idx.kspace_encode_step_1 + line_offset, :] = 1 #If last scan in buffer, do FFT and fill image header if acq.isFlagSet(ismrmrd.ACQ_LAST_IN_ENCODE_STEP1) or acq.isFlagSet( ismrmrd.ACQ_LAST_IN_SLICE): img_head = copy.deepcopy(self.header_proto) img_head.position = acq.position img_head.read_dir = acq.read_dir img_head.phase_dir = acq.phase_dir img_head.slice_dir = acq.slice_dir img_head.patient_table_position = acq.patient_table_position img_head.acquisition_time_stamp = acq.acquisition_time_stamp img_head.slice = acq.idx.slice img_head.channels = 1 scale = self.samp_mask.size / (1.0 * np.sum(self.samp_mask[:])) #We have not yet calculated unmixing coefficients if self.unmix is None: self.calib_buffer.append((img_head, self.buffer.copy())) self.buffer[:] = 0 self.samp_mask[:] = 0 if len(self.calib_buffer) >= self.calib_frames: cal_data = np.zeros(self.calib_buffer[0][1].shape, dtype=np.complex64) for c in self.calib_buffer: cal_data = cal_data + c[1] mask = np.squeeze(np.sum(np.abs(cal_data), 0)) mask = np.ones(mask.shape) * (np.abs(mask) > 0.0) target = None #cal_data[0:8,:,:] coil_images = transform.transform_kspace_to_image(cal_data, dim=(1, 2)) (csm, rho) = coils.calculate_csm_walsh(coil_images) if self.method == 'grappa': self.unmix, self.gmap = grappa.calculate_grappa_unmixing( cal_data, self.acc_factor, data_mask=mask, kernel_size=(4, 5), csm=csm) elif self.method == 'sense': self.unmix, self.gmap = sense.calculate_sense_unmixing( self.acc_factor, csm) else: raise Exception('Unknown parallel imaging method: ' + str(self.method)) for c in self.calib_buffer: recon = transform.transform_kspace_to_image( c[1], dim=(1, 2)) * np.sqrt(scale) recon = np.squeeze(np.sum(recon * self.unmix, 0)) self.put_next(c[0], recon, *args) return 0 if self.unmix is None: raise Exception( "We should never reach this point without unmixing coefficients" ) recon = transform.transform_kspace_to_image( self.buffer, dim=(1, 2)) * np.sqrt(scale) recon = np.squeeze(np.sum(recon * self.unmix, 0)) self.buffer[:] = 0 self.samp_mask[:] = 0 self.put_next(img_head, recon, *args) return 0
#%% # Basic setup import numpy as np import scipy as sp from ismrmrdtools import sense, grappa, show, simulation, transform, coils #%% # import some data exercise_data = sp.io.loadmat("hansen_exercises2.mat") csm = np.transpose(exercise_data["smaps"]) pat = np.transpose(exercise_data["sp"]) data = np.transpose(exercise_data["data"]) kspace = np.logical_or(pat == 1, pat == 3).astype("float32") * (data) acc_factor = 4 alias_img = transform.transform_kspace_to_image(kspace, dim=(1, 2)) * np.sqrt(acc_factor) show.imshow(abs(alias_img)) (unmix_grappa, gmap_grappa) = grappa.calculate_grappa_unmixing( data, acc_factor, data_mask=pat > 1, csm=csm, kernel_size=(4, 5) ) # (unmix_grappa,gmap_grappa) = grappa.calculate_grappa_unmixing(data, acc_factor, data_mask=pat>1) show.imshow(abs(gmap_grappa), colorbar=True) recon_grappa = np.squeeze(np.sum(alias_img * unmix_grappa, 0)) show.imshow(abs(recon_grappa), colorbar=True) sp.io.savemat( "tmp_data.mat", {"pat_py": pat, "data_py": data, "csm_py": csm, "alias_img_py": alias_img, "unmix_grappa_py": unmix_grappa}, )
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 test_bssfp_data(self): '''Sample bSSFP data set.''' dset = pyport(file=self.sample, debug=False) import numpy as np import ismrmrd import ismrmrd.xsd from ismrmrdtools import show, transform header = ismrmrd.xsd.CreateFromDocument(dset.read_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 is not None: nslices = enc.encodingLimits.slice.maximum + 1 else: nslices = 1 if enc.encodingLimits.average is not None: nreps = enc.encodingLimits.average.maximum + 1 else: nreps = 1 if enc.encodingLimits.contrast is not None: ncontrasts = enc.encodingLimits.contrast.maximum + 1 else: ncontrasts = 1 # TODO loop through the acquisitions looking for noise scans firstacq = 0 for acqnum in range(dset.number_of_acquisitions()): acq = dset.read_acquisition(acqnum) # TODO: Currently ignoring noise scans if acq.isFlagSet(ismrmrd.ACQ_IS_NOISE_MEASUREMENT): print("Found noise scan at acq ", acqnum) continue else: firstacq = acqnum print("Imaging acquisition starts acq ", acqnum) break # Initialiaze a storage array all_data = np.zeros( (nreps, ncontrasts, nslices, ncoils, eNz, eNy, rNx), dtype=np.complex64) #pylint: disable=E1101 # Loop through the rest of the acquisitions and stuff for acqnum in range(firstacq, dset.number_of_acquisitions()): acq = dset.read_acquisition(acqnum) # TODO: this is where we would apply noise pre-whitening # Remove oversampling if needed if eNx != rNx: xline = transform.transform_kspace_to_image(acq.data, [1]) x0 = int((eNx - rNx) / 2) x1 = int((eNx - rNx) / 2 + rNx) xline = xline[:, x0:x1] acq.resize(rNx, acq.active_channels, acq.trajectory_dimensions) #pylint: disable=E1101 acq.center_sample = int(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.average #pylint: disable=E1101 contrast = acq.idx.contrast #pylint: disable=E1101 slise = acq.idx.slice #pylint: disable=E1101 y = acq.idx.kspace_encode_step_1 #pylint: disable=E1101 z = acq.idx.kspace_encode_step_2 #pylint: disable=E1101 all_data[rep, contrast, slise, :, z, y, :] = acq.data # Reconstruct images images = np.zeros((nreps, ncontrasts, nslices, eNz, eNy, rNx), dtype=np.float32) #pylint: disable=E1101 for rep in range(nreps): for contrast in range(ncontrasts): for slise in range(nslices): # FFT if eNz > 1: #3D im = transform.transform_kspace_to_image( all_data[rep, contrast, slise, ...], [1, 2, 3]) else: #2D im = transform.transform_kspace_to_image( all_data[rep, contrast, slise, :, 0, ...], [1, 2]) # Sum of squares im = np.sqrt(np.sum(np.abs(im)**2, 0)) # Stuff into the output if eNz > 1: #3D images[rep, contrast, slise, ...] = im else: #2D images[rep, contrast, slise, 0, ...] = im # Show an image show.imshow(np.squeeze(images[0, 0, 0, ...]))
def process(self, recondata): # receive kspace data and # extract acq_data and acq_header array_acq_headers = recondata[0].data.headers kspace_data = recondata[0].data.data try: if recondata[0].ref.data is not None: print("reference data exist") print( np.shape(recondata[0].ref.data) ) # only for repetition 0 # il faut creer le bucket recon grappa except: print("reference data not exist") # ifft image = transform.transform_kspace_to_image(kspace_data, dim=(0, 1, 2)) # create a new IsmrmrdImageArray array_data = IsmrmrdImageArray() # attache the images to the IsmrmrdImageArray array_data.data = image # get dimension for the acq_headers dims_header = np.shape(recondata[0].data.headers) # get one header with typical info acq = np.ravel(array_acq_headers)[0] headers_list = [] base_header = ismrmrd.ImageHeader() base_header.version = 2 ndims_image = np.shape(image) base_header.channels = ndims_image[3] base_header.matrix_size = (image.shape[0], image.shape[1], image.shape[2]) print((image.shape[0], image.shape[1], image.shape[2])) base_header.position = acq.position base_header.read_dir = acq.read_dir base_header.phase_dir = acq.phase_dir base_header.slice_dir = acq.slice_dir base_header.patient_table_position = acq.patient_table_position base_header.acquisition_time_stamp = acq.acquisition_time_stamp base_header.image_index = 0 base_header.image_series_index = 0 base_header.data_type = ismrmrd.DATATYPE_CXFLOAT base_header.image_type = ismrmrd.IMTYPE_MAGNITUDE print("ready to list") for slc in range(0, dims_header[4]): for n in range(0, dims_header[3]): for s in range(0, dims_header[2]): #for e2 in range(0, dims_header[1]): # for e1 in range(0, dims_header[0]): headers_list.append(base_header) array_headers_test = np.array(headers_list, dtype=np.dtype(object)) print(type(array_headers_test)) print(np.shape(array_headers_test)) array_headers_test = np.reshape( array_headers_test, (dims_header[2], dims_header[3], dims_header[4])) print(type(array_headers_test)) print(np.shape(array_headers_test)) print("---> ok 0") # how to copy acquisition header into image header in python ? for slc in range(0, dims_header[4]): for n in range(0, dims_header[3]): for s in range(0, dims_header[2]): # for e2 in range(0, dims_header[1]): # for e1 in range(0, dims_header[0]): array_headers_test[s, n, slc].slice = slc #print(s,n,slc) #print(type(array_headers_test[s,n,slc])) #print(array_headers_test[s,n,slc].slice) #print("---> ok 1") # print(np.shape(array_image_header)) # attache the image headers to the IsmrmrdImageArray array_data.headers = array_headers_test #print("---> ok 2") # Return image to Gadgetron print(np.shape(array_data.data)) print(np.shape(array_data.headers)) print(type(array_data.data)) print(type(array_data.headers)) print(type(array_data)) # send the data to the next gadget for slc in range(0, dims_header[4]): for n in range(0, dims_header[3]): for s in range(0, dims_header[2]): #print("send out image %d-%d-%d" % (s, n, slc)) a = array_data.data[:, :, :, :, s, n, slc] #array_data.headers[s,n,slc].slice=slc #print(a.shape, array_data.headers[s,n,slc].slice) self.put_next(array_data.headers[s, n, slc], a) #self.put_next( [IsmrmrdReconBit(array_data.headers, array_data.data)] , ) print("----------------------------------------------") return 0
for phase in range(nphases): for rep in range(nreps): for contrast in range(ncontrasts): for slice in range(nslices): # FFT if eNz > 1: #3D if args.writeBIN: im = transform.fftn( np.squeeze( all_data[set_, avg, phase, rep, contrast, slice, :, :, :, :])) else: im = transform.transform_kspace_to_image( all_data[set_, avg, phase, rep, contrast, slice, :, :, :, :], [1, 2, 3]) else: #2D if args.writeBIN: im = transform.fftn( np.squeeze(all_data[set_, avg, phase, rep, contrast, slice, :, 0, :, :])) else: im = transform.transform_kspace_to_image( all_data[set_, avg, phase, rep, contrast, slice, :, 0, :, :], [1, 2])
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
print("Imaging acquisition starts acq ", acqnum) break # Initialiaze a storage array 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) # TODO: this is where we would apply noise pre-whitening # Remove oversampling if needed if eNx != rNx: xline = transform.transform_kspace_to_image(acq.data, [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 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, :] = acq.data
1], "/ xcenter: ", xcenter, "databuff.shape: ", databuff.shape #databuff[:,eNx/2-xcenter:eNx/2-xcenter+acq.data.shape[1]] = acq.data if xcenter == 0: databuff = acq.data else: if (xcenter - acq.data.shape[1] / 2) < 0: databuff[:, 0:acq.data.shape[1]] = acq.data else: #databuff[:,xcenter-acq.data.shape[1]/2:xcenter+acq.data.shape[1]/2] = acq.data databuff = acq.data #databuff = acq.data if args.removeOS: print "removeOS" xline = transform.transform_kspace_to_image(databuff, [1]) x0 = (eNx - rNx) / 2 x1 = (eNx - rNx) / 2 + rNx / 2 xline = xline[:, x0:x1] databuff.resize(rNx, acq.active_channels, acq.trajectory_dimensions) acq.center_sample = rNx / 2 # need to use the [:] notation here to fill the data databuff = transform.transform_image_to_kspace(xline, [1]) #print "databuff.shape=", databuff.shape print "seg", seg, " / avg", avg, " / set_", set_, " / rep", rep, " / contrast", contrast, " / slice_", slice, " / xcenter", xcenter, " / y", y, " / z", z if acq.isFlagSet(ismrmrd.ACQ_IS_PARALLEL_CALIBRATION): print "calibration data: acq:", acqnum all_data_calib[seg, set_, avg, phase, rep, contrast, slice, :, z, y, :] = databuff
print("Imaging acquisition starts acq ", acqnum) break # Initialiaze a storage array 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) # TODO: this is where we would apply noise pre-whitening # Remove oversampling if needed if eNx != rNx: xline = transform.transform_kspace_to_image(acq.data, [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 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, :] = acq.data
#Basic setup import numpy as np import scipy as sp from ismrmrdtools import sense, grappa, show, simulation, transform,coils from importlib import reload #%% #import some data exercise_data = sp.io.loadmat('hansen_exercises2.mat') csm = np.transpose(exercise_data['smaps']) pat = np.transpose(exercise_data['sp']) data = np.transpose(exercise_data['data']) kspace = np.logical_or(pat==1,pat==3).astype('float32')*(data) acc_factor = 4 alias_img = transform.transform_kspace_to_image(kspace,dim=(1,2)) * np.sqrt(acc_factor) show.imshow(abs(alias_img)) (unmix_grappa,gmap_grappa) = grappa.calculate_grappa_unmixing(data, acc_factor, data_mask=pat>1, csm=csm,kernel_size=(4,5)) #(unmix_grappa,gmap_grappa) = grappa.calculate_grappa_unmixing(data, acc_factor, data_mask=pat>1) show.imshow(abs(gmap_grappa),colorbar=True) recon_grappa = np.squeeze(np.sum(alias_img * unmix_grappa,0)) show.imshow(abs(recon_grappa),colorbar=True) sp.io.savemat('tmp_data.mat',{'pat_py': pat,'data_py': data,'csm_py': csm,'alias_img_py':alias_img,'unmix_grappa_py':unmix_grappa}) #%% #Reload some modules reload(show) reload(sense) reload(grappa)
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 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, :] = acq.data