def apply_affine_itk_transform_on_image(input_image, transform, center, reference_image=None, order=None): """ """ input_data = np.float32(input_image.get_data()) if reference_image is None: reference_image = input_image #set the interpolation order to 1 if not specified if order is None: order = 1 ref_data = np.float32(reference_image.get_data()) #create index for the reference space i = np.arange(0, ref_data.shape[0]) j = np.arange(0, ref_data.shape[1]) k = np.arange(0, ref_data.shape[2]) iv, jv, kv = np.meshgrid(i, j, k, indexing='ij') iv = np.reshape(iv, (-1)) jv = np.reshape(jv, (-1)) kv = np.reshape(kv, (-1)) #convert the transform from itk (LPS) to nibabel (RAS) nb_transform, nb_center = convert_itk_transform_to_affine_transform( transform, center) #compute the coordinates in the input image pointset = np.zeros((4, iv.shape[0])) pointset[0, :] = iv pointset[1, :] = jv pointset[2, :] = kv pointset[3, :] = np.ones((iv.shape[0])) #no need to specify the center here because it is included in itk-based nb_transform #pointset = transform_a_set_of_points(pointset,nb_transform,reference_image.affine,np.linalg.inv(input_image.affine)) pointset = transform_a_set_of_points(pointset, nb_transform, reference_image.affine, np.linalg.inv(input_image.affine), nb_center) #compute the interpolation val = np.zeros(iv.shape) map_coordinates(input_data, [pointset[0, :], pointset[1, :], pointset[2, :]], output=val, order=order) output_data = np.reshape(val, ref_data.shape) return nibabel.Nifti1Image(output_data, reference_image.affine)
def apply_affine_itk_transform_on_image(input_image, transform, center, reference_image=None, order=None): """ """ input_data = np.float32(input_image.get_data()) if reference_image is None: reference_image = input_image #set the interpolation order to 1 if not specified if order is None: order = 1 ref_data = np.float32(reference_image.get_data()) #create index for the reference space i = np.arange(0,ref_data.shape[0]) j = np.arange(0,ref_data.shape[1]) k = np.arange(0,ref_data.shape[2]) iv,jv,kv = np.meshgrid(i,j,k,indexing='ij') iv = np.reshape(iv,(-1)) jv = np.reshape(jv,(-1)) kv = np.reshape(kv,(-1)) #convert the transform from itk (LPS) to nibabel (RAS) nb_transform, nb_center = convert_itk_transform_to_affine_transform(transform,center) #compute the coordinates in the input image pointset = np.zeros((4,iv.shape[0])) pointset[0,:] = iv pointset[1,:] = jv pointset[2,:] = kv pointset[3,:] = np.ones((iv.shape[0])) #no need to specify the center here because it is included in itk-based nb_transform #pointset = transform_a_set_of_points(pointset,nb_transform,reference_image.affine,np.linalg.inv(input_image.affine)) pointset = transform_a_set_of_points(pointset,nb_transform,reference_image.affine,np.linalg.inv(input_image.affine),nb_center) #compute the interpolation val = np.zeros(iv.shape) map_coordinates(input_data,[pointset[0,:],pointset[1,:],pointset[2,:]],output=val,order=order) output_data = np.reshape(val,ref_data.shape) return nibabel.Nifti1Image(output_data, reference_image.affine)
def compute_H(y, x, w2wtransform, psf, mask): """ Compute the matrix H, y = Hx y : low resolution x : high resolution Parameters ---------- y : one nibabel image An array containing the lr resolution pixels (list of array) x : one nibabel image An array containing the hr resolution pixels (array) w2w_transform : ndarray Transform from world to world coordinate (y to x), as a 2D array (homogeneous matrix) psf : ndarray PSF kernel mask : one nibabel image List of array containing points to process Returns ------- H : sparse matrix Sparse matrix H corresponding to the observation model y=Hx """ print 'Computing the observation matrix H (for each low-resolution image)' t = time() psfCenter = (np.array(psf.shape) -1.0 )/2.0 LRSpacing = np.float32(np.array(y.header['pixdim'][1:4])) ydata = np.float32(y.get_data()) lookup_lr_index = np.arange(ydata.size).reshape(ydata.shape).astype(int) HRSize = np.float32(np.array(x.header['dim'][1:4])) HRSpacing = np.float32(np.array(x.header['pixdim'][1:4])) xdata = np.float32(x.get_data()) lookup_hr_index = np.arange(xdata.size).reshape(xdata.shape) #Create a large empty sparse matrix H = lil_matrix((np.int(ydata.size),np.int(xdata.size))) #Compute the inverse of the affine matrix (from X to world coordinate) inverseMatrixX = np.linalg.inv(x.affine) #tmpH is a temporary variable to avoid many access to the sparse matrix H tmpH = np.zeros((xdata.size)) ratioi = HRSpacing[0]/LRSpacing[0] ratioj = HRSpacing[1]/LRSpacing[1] ratiok = HRSpacing[2]/LRSpacing[2] #Precompute PSF shift (expressed in the coordinate system of current LR image psfShift = np.zeros((4,psf.size)) psfValues = np.zeros((psf.size)) index = 0 for ipsf in range(psf.shape[0]): for jpsf in range(psf.shape[1]): for kpsf in range(psf.shape[2]): psfShift[0,index] = (ipsf - psfCenter[0])*ratioi psfShift[1,index] = (jpsf - psfCenter[1])*ratioj psfShift[2,index] = (kpsf - psfCenter[2])*ratiok psfValues[index] = psf[ipsf,jpsf,kpsf] index+=1 #convert the transform from itk (LPS) to nibabel (RAS) transform, center = convert_itk_transform_to_affine_transform(w2wtransform[0],w2wtransform[1]) #Get index to process in the current LR image nonzeroMask = np.nonzero(mask.get_data()) for i,j,k in zip(nonzeroMask[0],nonzeroMask[1],nonzeroMask[2]): #Compute the index of current voxel in y indexlr = lookup_lr_index[i,j,k] #Loop over PSF elements (put all psf points into psfPoints array) psfPoints = np.array([[i],[j],[k],[1]]) + psfShift #Transform index to world coordinate (y) #Transform world coordinate (y) to world coordinate (x) #Transform world coordinate (x) to index #These three transforms are applied using the following function: pointset = transform_a_set_of_points(psfPoints,np.linalg.inv(transform),y.affine,inverseMatrixX,center) #pointset = transform_a_set_of_points(psfPoints,transform,y[l].affine,np.linalg.inv(x.affine),center) #Do psf weights interpolation on the grid of x (HR image) #we do here basic linear interpolation of the weights floorPoints = np.int32(np.floor(pointset)) w1 = pointset - floorPoints w2 = 1 - w1 #weights for linear interpolation w = np.zeros((8,psf.size)) w[0,:] = w2[0,:] * w2[1,:] * w2[2,:] w[1,:] = w1[0,:] * w2[1,:] * w2[2,:] w[2,:] = w1[0,:] * w1[1,:] * w2[2,:] w[3,:] = w1[0,:] * w1[1,:] * w1[2,:] w[4,:] = w2[0,:] * w1[1,:] * w1[2,:] w[5,:] = w1[0,:] * w2[1,:] * w1[2,:] w[6,:] = w2[0,:] * w2[1,:] * w1[2,:] w[7,:] = w2[0,:] * w1[1,:] * w2[2,:] #To fill efficiently the sparse matrix H, we need to store nonzero elements index. #Indeed, finding non zero element is very long in a vector (size of x) tmpHList = [] #Loop over all transformed PSF points to accumulate weights for f,weight in zip(floorPoints.T,w.T): if (f>=0).all() and (f[0:3]<HRSize-1).all(): indexhr = lookup_hr_index[f[0],f[1],f[2]] tmpH[indexhr] += weight[0] tmpHList.append(indexhr) indexhr = lookup_hr_index[f[0]+1,f[1],f[2]] tmpH[indexhr] += weight[1] tmpHList.append(indexhr) indexhr = lookup_hr_index[f[0]+1,f[1]+1,f[2]] tmpH[indexhr] += weight[2] tmpHList.append(indexhr) indexhr = lookup_hr_index[f[0]+1,f[1]+1,f[2]+1] tmpH[indexhr] += weight[3] tmpHList.append(indexhr) indexhr = lookup_hr_index[f[0],f[1]+1,f[2]+1] tmpH[indexhr] += weight[4] tmpHList.append(indexhr) indexhr = lookup_hr_index[f[0]+1,f[1],f[2]+1] tmpH[indexhr] += weight[5] tmpHList.append(indexhr) indexhr = lookup_hr_index[f[0],f[1],f[2]+1] tmpH[indexhr] += weight[6] tmpHList.append(indexhr) indexhr = lookup_hr_index[f[0],f[1]+1,f[2]] tmpH[indexhr] += weight[7] tmpHList.append(indexhr) #H[lookup_lr_index[i,j,k],lookup_hr_index[f[0],f[1],f[2]]] = 1.0 #Get the list of index to update in H tmpHIndex = np.unique(np.asarray(tmpHList)) if tmpHIndex.size > 0: #Fill the corresponding line of the sparse matrix H[indexlr,tmpHIndex] = tmpH[tmpHIndex] #Set tmpH to zero tmpH[tmpHIndex] = 0 #normalization of rows (using sklearn) H_normalized = normalize(H, norm='l1', axis=1) print 'Computation done in '+str(time()-t)+' s' return H_normalized
def compute_H(y, x, w2wtransform, psf, mask): """ Compute the matrix H, y = Hx y : low resolution x : high resolution Parameters ---------- y : one nibabel image An array containing the lr resolution pixels (list of array) x : one nibabel image An array containing the hr resolution pixels (array) w2w_transform : ndarray Transform from world to world coordinate (y to x), as a 2D array (homogeneous matrix) psf : ndarray PSF kernel mask : one nibabel image List of array containing points to process Returns ------- H : sparse matrix Sparse matrix H corresponding to the observation model y=Hx """ print('Computing the observation matrix H (for each low-resolution image)') t = time() psfCenter = (np.array(psf.shape) -1.0 )/2.0 LRSpacing = np.float32(np.array(y.header['pixdim'][1:4])) ydata = np.float32(y.get_data()) lookup_lr_index = np.arange(ydata.size).reshape(ydata.shape).astype(int) HRSize = np.float32(np.array(x.header['dim'][1:4])) HRSpacing = np.float32(np.array(x.header['pixdim'][1:4])) xdata = np.float32(x.get_data()) lookup_hr_index = np.arange(xdata.size).reshape(xdata.shape) #Create a large empty sparse matrix H = lil_matrix((np.int(ydata.size),np.int(xdata.size))) #Compute the inverse of the affine matrix (from X to world coordinate) inverseMatrixX = np.linalg.inv(x.affine) #tmpH is a temporary variable to avoid many access to the sparse matrix H tmpH = np.zeros((xdata.size)) ratioi = HRSpacing[0]/LRSpacing[0] ratioj = HRSpacing[1]/LRSpacing[1] ratiok = HRSpacing[2]/LRSpacing[2] #Precompute PSF shift (expressed in the coordinate system of current LR image psfShift = np.zeros((4,psf.size)) psfValues = np.zeros((psf.size)) index = 0 for ipsf in range(psf.shape[0]): for jpsf in range(psf.shape[1]): for kpsf in range(psf.shape[2]): psfShift[0,index] = (ipsf - psfCenter[0])*ratioi psfShift[1,index] = (jpsf - psfCenter[1])*ratioj psfShift[2,index] = (kpsf - psfCenter[2])*ratiok psfValues[index] = psf[ipsf,jpsf,kpsf] index+=1 #convert the transform from itk (LPS) to nibabel (RAS) transform, center = convert_itk_transform_to_affine_transform(w2wtransform[0],w2wtransform[1]) #Get index to process in the current LR image nonzeroMask = np.nonzero(mask.get_data()) for i,j,k in zip(nonzeroMask[0],nonzeroMask[1],nonzeroMask[2]): #Compute the index of current voxel in y indexlr = lookup_lr_index[i,j,k] #Loop over PSF elements (put all psf points into psfPoints array) psfPoints = np.array([[i],[j],[k],[1]]) + psfShift #Transform index to world coordinate (y) #Transform world coordinate (y) to world coordinate (x) #Transform world coordinate (x) to index #These three transforms are applied using the following function: pointset = transform_a_set_of_points(psfPoints,np.linalg.inv(transform),y.affine,inverseMatrixX,center) #pointset = transform_a_set_of_points(psfPoints,transform,y[l].affine,np.linalg.inv(x.affine),center) #Do psf weights interpolation on the grid of x (HR image) #we do here basic linear interpolation of the weights floorPoints = np.int32(np.floor(pointset)) w1 = pointset - floorPoints w2 = 1 - w1 #weights for linear interpolation w = np.zeros((8,psf.size)) w[0,:] = w2[0,:] * w2[1,:] * w2[2,:] w[1,:] = w1[0,:] * w2[1,:] * w2[2,:] w[2,:] = w1[0,:] * w1[1,:] * w2[2,:] w[3,:] = w1[0,:] * w1[1,:] * w1[2,:] w[4,:] = w2[0,:] * w1[1,:] * w1[2,:] w[5,:] = w1[0,:] * w2[1,:] * w1[2,:] w[6,:] = w2[0,:] * w2[1,:] * w1[2,:] w[7,:] = w2[0,:] * w1[1,:] * w2[2,:] #To fill efficiently the sparse matrix H, we need to store nonzero elements index. #Indeed, finding non zero element is very long in a vector (size of x) tmpHList = [] #Loop over all transformed PSF points to accumulate weights for f,weight in zip(floorPoints.T,w.T): if (f>=0).all() and (f[0:3]<HRSize-1).all(): indexhr = lookup_hr_index[f[0],f[1],f[2]] tmpH[indexhr] += weight[0] tmpHList.append(indexhr) indexhr = lookup_hr_index[f[0]+1,f[1],f[2]] tmpH[indexhr] += weight[1] tmpHList.append(indexhr) indexhr = lookup_hr_index[f[0]+1,f[1]+1,f[2]] tmpH[indexhr] += weight[2] tmpHList.append(indexhr) indexhr = lookup_hr_index[f[0]+1,f[1]+1,f[2]+1] tmpH[indexhr] += weight[3] tmpHList.append(indexhr) indexhr = lookup_hr_index[f[0],f[1]+1,f[2]+1] tmpH[indexhr] += weight[4] tmpHList.append(indexhr) indexhr = lookup_hr_index[f[0]+1,f[1],f[2]+1] tmpH[indexhr] += weight[5] tmpHList.append(indexhr) indexhr = lookup_hr_index[f[0],f[1],f[2]+1] tmpH[indexhr] += weight[6] tmpHList.append(indexhr) indexhr = lookup_hr_index[f[0],f[1]+1,f[2]] tmpH[indexhr] += weight[7] tmpHList.append(indexhr) #H[lookup_lr_index[i,j,k],lookup_hr_index[f[0],f[1],f[2]]] = 1.0 #Get the list of index to update in H tmpHIndex = np.unique(np.asarray(tmpHList)) if tmpHIndex.size > 0: #Fill the corresponding line of the sparse matrix H[indexlr,tmpHIndex] = tmpH[tmpHIndex] #Set tmpH to zero tmpH[tmpHIndex] = 0 #normalization of rows (using sklearn) H_normalized = normalize(H, norm='l1', axis=1) print('Computation done in '+str(time()-t)+' s') return H_normalized