def test_compose_trsf(): #--- compose transformation trsf_inp, trsf_composed = BalTransformation(), BalTransformation() trsf_inp.read(trsf_arbitrary_path) trsf_composed.read(trsf_composed_path) trsf_out = compose_trsf([trsf_inp, trsf_inp, trsf_inp]) np.testing.assert_almost_equal(trsf_out.mat.to_np_array(), trsf_composed.mat.to_np_array())
def compose_trsf(list_trsf, template_img=None, param_str_1=COMPOSE_TRSF_DEFAULT, param_str_2=None): """ Composition of *BalTransformation* transformations Parameters ---------- :param list list_trsf: list of *BalTransformation* transformations :param *SpatialImage* template_img: optional, template_img is a *SpatialImage* specified for vectorfield composition :param str param_str_1: COMPOSE_TRSF_DEFAULT :param str param_str_2: optional, optional parameters Returns ---------- :return: res_trsf, *BalTransformation* transformation Examples ------- >>> res_trsf = compose_trsf([trsf_1, trsf_2, trsf_3]) >>> res_trsf = compose_trsf([trsf_1, trsf_2, trsf_3], template_img=template_img) """ # SR - 18/03 trsf_types = [list_trsf[ind].trsf_type for ind, val in enumerate(list_trsf)] ref = list_trsf[trsf_types.index(max(trsf_types))] # if template_img is not None and 12 (vectorfield transformation) # not in trsf_types, template_img is ignored if 12 in trsf_types and template_img is None: print('Specify a template image for output image geometry') raise NotImplementedError elif 12 in trsf_types and template_img is not None: if template_img.get_dim()==2: template_img = template_img.to_3D() x, y, z = template_img.get_shape() str_dims = ''.join(['-template-dim ', str(x), ' ', str(y), ' ', str(z)]) param_str_1 = ''.join([param_str_1, str_dims]) trsf_out = BalTransformation(trsf_type=ref.trsf_type, trsf_unit=ref.trsf_unit, c_bal_trsf=ref.c_struct) else: trsf_out = BalTransformation(trsf_type=ref.trsf_type, trsf_unit=ref.trsf_unit) # end modif mat_out = trsf_out.mat init_c_bal_matrix(mat_out.c_struct, l=4, c=4) allocate_c_bal_matrix(mat_out.c_struct, np.zeros((4, 4), dtype=np.float64)) ntrsf = len(list_trsf) lst = POINTER(BAL_TRSF) * ntrsf trsfs = lst(*[trsf.c_ptr for trsf in list_trsf]) libblockmatching.API_composeTrsf(trsfs, ntrsf, trsf_out.c_ptr, param_str_1, param_str_2) return trsf_out
def test_inv_trsf(): #--- inverse transformation trsf_inp, trsf_ref = BalTransformation(), BalTransformation() trsf_inp.read(trsf_arbitrary_path) #--- trsf_1 trsf_ref.read(inv_trsf_ref_path) #--- inv(trsf_1) trsf_out = inv_trsf(trsf_inp) ref, out = trsf_ref.mat.to_np_array(), trsf_out.mat.to_np_array() np.testing.assert_array_almost_equal(ref, out, decimal=8) trsf_inp.free() trsf_ref.free() trsf_out.free()
def test_plugin_deformable(self): #--- deformable registration floating_img = imread(data_path('time_0_cut.inr')) reference_img = imread(data_path('time_1_cut.inr')) deformable_trsf = data_path("deformable_0_1.trsf") trsf_inp = BalTransformation() trsf_inp.read(deformable_trsf) trsf_out, res = registration(floating_img, reference_img, method='deformable_registration') np.testing.assert_array_almost_equal(trsf_out.mat.to_np_array(), trsf_inp.mat.to_np_array(), decimal=6) trsf_out.free() trsf_inp.free() return
def test_blockmatching_rigid(self): #--- rigid registration floating_img = imread(data_path('time_0_cut.inr')) reference_img = imread(data_path('time_1_cut.inr')) rigid_trsf = data_path("rigid_0_1.trsf") trsf_out, res = blockmatching(floating_img, reference_img) trsf_inp = BalTransformation() trsf_inp.read(rigid_trsf) np.testing.assert_array_almost_equal(trsf_out.mat.to_np_array(), trsf_inp.mat.to_np_array(), decimal=6) trsf_out.free() trsf_inp.free() return
def create_trsf(template_img=None, param_str_1=CREATE_TRSF_DEFAULT, param_str_2=None, trsf_type=None, trsf_unit=None): """ Creation of classical *BalTransformation* transformations such as identity, translation, rotation,sinusoidal, random, etc. Parameters ---------- :param *SpatialImage* template_img: optional, template_img is a *SpatialImage* :param str param_str_1: CREATE_TRSF_DEFAULT, default is identity :param str param_str_2: optional, optional parameters :param *BalTransformationType* trsf_type: type of *BalTransformation* transformation (see enumTypeTransfo in bal_stddef) Default trsf_type is BalTransformation.AFFINE_3D :param *BalTransformationUnit* trsf_unit: unit of *BalTransformation* transformation (see enumUnitTransfo in bal_stddef) Default trsf_unit is BalTransformation.REAL_UNIT Returns ---------- :return: *BalTransformation* trsf_out, output transformation Example ------- >>> identity_trsf = create_trsf() """ if template_img is not None and isinstance(template_img, SpatialImage): if template_img.get_dim()==2: template_img = template_img.to_3D() x, y, z = template_img.get_shape() vx, vy, vz = template_img.get_voxelsize() val_dim = ''.join([' -template-dim ', str(x), ' ', str(y), ' ', str(z)]) val_vox = ''.join([' -template-voxel ', str(vx), ' ', str(vy), ' ', str(vz)]) param_str_1 = ''.join([param_str_1, str(val_dim), str(val_vox)]) bal_image = BalImage(template_img) else: template_img = None #raise NotImplementedError if trsf_type is None: trsf_type = BalTransformation.AFFINE_3D if trsf_unit is None: trsf_unit = BalTransformation.REAL_UNIT trsf_out = BalTransformation(trsf_type=trsf_type, trsf_unit=trsf_unit) mat_out = trsf_out.mat init_c_bal_matrix(mat_out.c_struct, l=4, c=4) allocate_c_bal_matrix(mat_out.c_struct, np.zeros((4, 4), dtype=np.float64)) libblockmatching.API_createTrsf(trsf_out.c_ptr, None if template_img is None else bal_image.c_ptr, param_str_1, param_str_2) return trsf_out
def inv_trsf(bal_transformation, template_img=None, param_str_1=INV_TRSF_DEFAULT, param_str_2=None): """ Inversion of a *BalTransformation* transformation Parameters ---------- :param *BalTransformation* bal_transformation: *BalTransformation*, input transformation :param template_img: optional, default is None. template_img is used for output image geometry and can be either SpatialImage or a list of dimensions :param str param_str_1: INV_TRSF_DEFAULT, default = '' :param str param_str_2: optional, optional parameters Returns ---------- :return: output *BalTransformation* transformation Example ------- >>> trsf_output = inv_trsf(trsf_input) """ if isinstance(bal_transformation, BalTransformation): if template_img is not None: if isinstance(template_img, SpatialImage): if template_img.get_dim()==2: template_img = template_img.to_3D() x, y, z = template_img.get_shape() vx, vy, vz = template_img.get_voxelsize() val_vox = ''.join([' -template-voxel ', str(vx), ' ', str(vy), ' ', str(vz)]) elif isinstance(template_img, list): if len(template_img)==3: x, y, z = template_img[0], template_img[1], template_img[2] elif len(template_img)==2: x, y, z = template_img[0], template_img[1], 1 val_vox = '' val_dim = ''.join([' -template-dim ', str(x), ' ', str(y), ' ', str(z)]) param_str_1 = ''.join([param_str_1, str(val_dim), str(val_vox)]) trsf_out = BalTransformation(trsf_type=bal_transformation.trsf_type, trsf_unit=bal_transformation.trsf_unit, c_bal_trsf=bal_transformation) libblockmatching.API_invTrsf(bal_transformation.c_ptr, trsf_out.c_ptr, param_str_1, param_str_2) return trsf_out else: raise TypeError('Input transformation must be a BalTransformation') return
def test_blockmatching_deformable(self): #--- deformable registration floating_img = imread(data_path('time_0_cut.inr')) reference_img = imread(data_path('time_1_cut.inr')) rigid_trsf = data_path("rigid_0_1.trsf") deformable_trsf = data_path("deformable_0_1.trsf") init_result_transformation = BalTransformation() init_result_transformation.read(rigid_trsf) param_str_2 = '-trsf-type vectorfield' trsf_out, res = blockmatching( floating_img, reference_img, init_result_transformation=init_result_transformation, left_transformation=None, param_str_2=param_str_2) trsf_inp = BalTransformation() trsf_inp.read(deformable_trsf) np.testing.assert_array_almost_equal(trsf_out.mat.to_np_array(), trsf_inp.mat.to_np_array(), decimal=6) trsf_out.free() trsf_inp.free() return
def test_blockmatching_deformable(self): #--- deformable registration floating_img = imread(data_path('time_0_cut.inr')) reference_img = imread(data_path('time_1_cut.inr')) rigid_trsf = data_path("rigid_0_1.trsf") deformable_trsf = data_path("deformable_0_1.trsf") init_result_transformation = BalTransformation() init_result_transformation.read(rigid_trsf) param_str_2 = '-trsf-type vectorfield' trsf_out, res = blockmatching(floating_img, reference_img, init_result_transformation=init_result_transformation, left_transformation=None, param_str_2=param_str_2) trsf_inp = BalTransformation() trsf_inp.read(deformable_trsf) np.testing.assert_array_almost_equal(trsf_out.mat.to_np_array(), trsf_inp.mat.to_np_array(), decimal=6) trsf_out.free() trsf_inp.free() return
def mean_trsfs(list_trsf): """ Mean trsfs (vectorfield) *BalTransformation* transformation Parameters ---------- :param list list_trsf: list of *BalTransformation* transformations (vectorfield type) Returns ---------- :return: *BalTransformation* trsf_out, output mean transformation Example ------- >>> trsf_out = mean_trsf([trsf_1, trsf_2, trsf_3]) """ conds_init = isinstance(list_trsf, list) and len(list_trsf)>=2 conds_list_trsf = [0 if (isinstance(trsf, BalTransformation) and trsf.trsf_type==12) else 1 for trsf in list_trsf] conds_inst = len(np.unique(conds_list_trsf))==1 and 1 not in conds_list_trsf if conds_init and conds_inst: # list of BalTransformation transformations (vectorfield) spatial_image_vx = [trsf.vx.to_spatial_image() for trsf in list_trsf] sum_spatial_image_vx = np.zeros_like(spatial_image_vx[0]) for ind, sp_img in enumerate(spatial_image_vx): sum_spatial_image_vx = sum_spatial_image_vx + sp_img mean_spatial_image_vx = sum_spatial_image_vx/len(spatial_image_vx) mean_spatial_image_vx = SpatialImage(mean_spatial_image_vx, voxelsize=spatial_image_vx[0].voxelsize) BalImage_vx = BalImage(mean_spatial_image_vx) spatial_image_vy = [trsf.vy.to_spatial_image() for trsf in list_trsf] sum_spatial_image_vy = np.zeros_like(spatial_image_vy[0]) for ind, sp_img in enumerate(spatial_image_vy): sum_spatial_image_vy = sum_spatial_image_vy + sp_img mean_spatial_image_vy = sum_spatial_image_vy/len(spatial_image_vy) mean_spatial_image_vy = SpatialImage(mean_spatial_image_vy, voxelsize=spatial_image_vy[0].voxelsize) BalImage_vy = BalImage(mean_spatial_image_vy) spatial_image_vz = [trsf.vz.to_spatial_image() for trsf in list_trsf] sum_spatial_image_vz = np.zeros_like(spatial_image_vz[0]) for ind, sp_img in enumerate(spatial_image_vz): sum_spatial_image_vz = sum_spatial_image_vz + sp_img mean_spatial_image_vz = sum_spatial_image_vz/len(spatial_image_vz) mean_spatial_image_vz = SpatialImage(mean_spatial_image_vz, voxelsize=spatial_image_vz[0].voxelsize) BalImage_vz = BalImage(mean_spatial_image_vz) out_BAL_TRSF = BAL_TRSF() #--- BALTRSF instance out_BAL_TRSF_ptr = pointer(out_BAL_TRSF) libblockmatching.BAL_AllocTransformation(out_BAL_TRSF_ptr, list_trsf[0].trsf_type, pointer(list_trsf[0].vx.c_struct)) out_BAL_TRSF.transformation_unit = list_trsf[0].trsf_unit out_BAL_TRSF.mat = list_trsf[0].mat.c_struct #--- BAL_MATRIX instance out_BAL_TRSF.vx = BalImage_vx.c_struct #--- BALIMAGE instance out_BAL_TRSF.vy = BalImage_vy.c_struct #--- BALIMAGE instance out_BAL_TRSF.vz = BalImage_vz.c_struct #--- BALIMAGE instance trsf_out = BalTransformation(trsf_type=list_trsf[0].trsf_type, c_bal_trsf=out_BAL_TRSF) for ind, trsf in enumerate(list_trsf): trsf.free() return trsf_out else: print('Specify a list of BalTransformation transformations') return
def test_apply_trsf_deformable(): #--- apply transformation trsf_inp = BalTransformation() trsf_inp.read(trsf_deformable_path) img_res = apply_trsf(img_src, trsf_inp) np.testing.assert_equal(deformable_transformed_ref, img_res)
def fusion(list_images, iterations=None): """ Multiview reconstruction (registration) Parameters ---------- :param list list_images: list of input ``SpatialImage`` :param int iterations: number of iterations, optional. Default: 5 Returns ---------- :return: ``SpatialImage`` instance -- image and metadata Example ------- >>> from timagetk.util import data_path >>> from timagetk.components import imread >>> from timagetk.algorithms import fusion >>> vues = [0, 1, 2] >>> list_images = [imread(data_path('fusion_img_' + str(vue) + '.inr')) for vue in vues] >>> fus_img = fusion(list_images) """ if iterations is None: iterations = 5 else: iterations = int(abs(iterations)) #--- check: list of SpatialImage images conds_init = isinstance(list_images, list) and len(list_images) >= 2 conds_list_img = [ 0 if isinstance(sp_img, SpatialImage) else 1 for sp_img in list_images ] #--- end check if conds_init and 1 not in conds_list_img: succ_ref_img = [] vox_list = [sp_img.get_voxelsize() for sp_img in list_images] vox_list = [i for i in itertools.chain.from_iterable(vox_list) ] # voxel list ext_list = [sp_img.get_extent() for sp_img in list_images] ext_list = [i for i in itertools.chain.from_iterable(ext_list) ] # extent list if list_images[0].get_dim() == 3: min_vox, val = np.min(vox_list), int( np.max(ext_list) / np.min(vox_list)) tmp_arr = np.zeros((val, val, val), dtype=list_images[0].dtype) template_img = SpatialImage(tmp_arr, voxelsize=[min_vox, min_vox, min_vox]) init_ref = apply_trsf(list_images[0], bal_transformation=None, template_img=template_img) succ_ref_img.append(init_ref) init_trsf_list, init_img_list = [], [] for ind, sp_img in enumerate(list_images): if ind > 0: trsf_rig, res_rig = blockmatching( sp_img, init_ref, param_str_2='-trsf-type rigid -py-ll 1') trsf_aff, res_aff = blockmatching( sp_img, init_ref, left_transformation=trsf_rig, param_str_2='-trsf-type affine') tmp_trsf = compose_trsf([trsf_rig, trsf_aff]) trsf_def, res_def = blockmatching( sp_img, init_ref, init_result_transformation=tmp_trsf, param_str_2='-trsf-type vectorfield') out_trsf = BalTransformation(c_bal_trsf=trsf_def) init_trsf_list.append(out_trsf) init_img_list.append(res_def) init_img_list.append(init_ref) mean_ref = mean_images(init_img_list) mean_trsf = mean_trsfs(init_trsf_list) mean_trsf_inv = inv_trsf(mean_trsf) mean_ref_update = apply_trsf(mean_ref, mean_trsf_inv, template_img=template_img) succ_ref_img.append(mean_ref_update) for index in range(0, iterations): init_trsf_list, init_img_list = [], [] for ind, sp_img in enumerate(list_images): trsf_rig, res_rig = blockmatching( sp_img, mean_ref_update, param_str_2='-trsf-type rigid -py-ll 1') trsf_aff, res_aff = blockmatching( sp_img, mean_ref_update, left_transformation=trsf_rig, param_str_2='-trsf-type affine') tmp_trsf = compose_trsf([trsf_rig, trsf_aff]) trsf_def, res_def = blockmatching( sp_img, mean_ref_update, init_result_transformation=tmp_trsf, param_str_2='-trsf-type vectorfield') out_trsf = BalTransformation(c_bal_trsf=trsf_def) init_trsf_list.append(out_trsf) init_img_list.append(res_def) init_img_list.append(mean_ref_update) mean_ref = mean_images(init_img_list) mean_trsf = mean_trsfs(init_trsf_list) mean_trsf_inv = inv_trsf(mean_trsf) mean_ref_update = apply_trsf(mean_ref, mean_trsf_inv, template_img=template_img) succ_ref_img.append(mean_ref_update) return succ_ref_img[-1] else: print('Incorrect specification') return
def blockmatching(floating_image, reference_image, init_result_transformation=None, left_transformation=None, param_str_1=BLOCKMATCHING_DEFAULT, param_str_2=None, dtype=None): """ Registration algorithm. Registers a floating_image onto a reference_image. Parameters ---------- :param *SpatialImage* floating_image: *SpatialImage*, floating image :param *SpatialImage* reference_image: *SpatialImage*, reference image :param *BalTransformation* init_result_transformation: optional, BalTransformation init transformation. By default init_result_transformation is None If given, init_result_transformation is modified as result :param *BalTransformation* left_transformation: optional, BalTransformation left transformation By default left_transformation is None :param str param_str1: by default a rigid registration is computed and param_str_1=BLOCKMATCHING_DEFAULT='-trsf-type rigid' :param str param_str_2: optional, type string :param *np.dtype* dtype: optional, output image type. By default, the output type is equal to the input type. Returns ---------- :return: ``BalTransformation`` transformation -- trsf_out :return: ``SpatialImage`` instance -- res_img, image and metadata Example ------- >>> from timagetk.util import data_path >>> from timagetk.components import imread >>> flo_path = data_path('time_0_cut.inr') >>> floating_image = imread(flo_path) >>> ref_path = data_path('time_1_cut.inr') >>> reference_image = imread(ref_path) >>> trsf_rig, res_rig = blockmatching(floating_image, reference_image) # rigid registration >>> param_str_2 = '-trsf-type vectorfield' >>> trsf_def, res_def = blockmatching(floating_image, reference_image, init_result_transformation=trsf_rig, param_str_2=param_str_2) # deformable registration """ if isinstance(floating_image, SpatialImage) and isinstance( reference_image, SpatialImage): bal_floating_image, bal_reference_image = BalImage( floating_image), BalImage(reference_image) kwds = spatial_image_to_bal_image_fields(reference_image) if dtype is not None: kwds['np_type'] = dtype c_img_res = BAL_IMAGE() init_c_bal_image(c_img_res, **kwds) allocate_c_bal_image(c_img_res, np.ndarray(kwds['shape'], kwds['np_type'])) img_res = BalImage(c_bal_image=c_img_res) # --- old API FRED, see plugins # if transformation_type: # param_str_2 = '-trsf-type '+transformation_type+' '+param_str # else: # param_str_2 = param_str trsf_out_ptr = libblockmatching.API_blockmatching( bal_floating_image.c_ptr, bal_reference_image.c_ptr, pointer(c_img_res), left_transformation.c_ptr if left_transformation else None, init_result_transformation.c_ptr if init_result_transformation else None, param_str_1, param_str_2) if init_result_transformation is not None: # If init_result_transformation is given, this transformation is modified # during registration and trsf_out is init_result_transformation trsf_out = init_result_transformation else: trsf_out = BalTransformation(c_bal_trsf=trsf_out_ptr.contents) sp_img = img_res.to_spatial_image() bal_floating_image.free(), bal_reference_image.free(), img_res.free() return trsf_out, sp_img else: raise TypeError('Input images must be SpatialImage instances') return