Example #1
0
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())
Example #2
0
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())
Example #3
0
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
Example #4
0
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
Example #7
0
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
Example #8
0
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()
Example #9
0
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
Example #10
0
 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
Example #12
0
        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
Example #13
0
 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
Example #14
0
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
Example #15
0
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)
Example #16
0
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
Example #17
0
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)
Example #18
0
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