def test_diffeomorphic_map_2d(): r""" Creates a random displacement field that exactly maps pixels from an input image to an output image. First a discrete random assignment between the images is generated, then each pair of mapped points are transformed to the physical space by assigning a pair of arbitrary, fixed affine matrices to input and output images, and finaly the difference between their positions is taken as the displacement vector. The resulting displacement, although operating in physical space, maps the points exactly (up to numerical precision). """ np.random.seed(2022966) domain_shape = (10, 10) codomain_shape = (10, 10) #create a simple affine transformation nr = domain_shape[0] nc = domain_shape[1] s = 1.1 t = 0.25 trans = np.array([[1, 0, -t*nr], [0, 1, -t*nc], [0, 0, 1]]) trans_inv = np.linalg.inv(trans) scale = np.array([[1*s, 0, 0], [0, 1*s, 0], [0, 0, 1]]) gt_affine = trans_inv.dot(scale.dot(trans)) #create the random displacement field domain_affine = gt_affine codomain_affine = gt_affine disp, assign = vfu.create_random_displacement_2d( np.array(domain_shape, dtype=np.int32), domain_affine,np.array(codomain_shape, dtype=np.int32), codomain_affine) disp = np.array(disp, dtype=floating) assign = np.array(assign) #create a random image (with decimal digits) to warp moving_image = np.ndarray(codomain_shape, dtype=floating) ns = np.size(moving_image) moving_image[...] = np.random.randint(0, 10, ns).reshape(codomain_shape) #set boundary values to zero so we don't test wrong interpolation due #to floating point precision moving_image[0,:] = 0 moving_image[-1,:] = 0 moving_image[:,0] = 0 moving_image[:,-1] = 0 #warp the moving image using the (exact) assignments expected = moving_image[(assign[...,0], assign[...,1])] #warp using a DiffeomorphicMap instance diff_map = imwarp.DiffeomorphicMap(2, domain_shape, domain_affine, domain_shape, domain_affine, codomain_shape, codomain_affine, None) diff_map.forward = disp #Verify that the transform method accepts different image types (note that #the actual image contained integer values, we don't want to test rounding) for type in [floating, np.float64, np.int64, np.int32]: moving_image = moving_image.astype(type) #warp using linear interpolation warped = diff_map.transform(moving_image, 'linear') #compare the images (the linear interpolation may introduce slight #precision errors) assert_array_almost_equal(warped, expected, decimal=5) #Now test the nearest neighbor interpolation warped = diff_map.transform(moving_image, 'nearest') #compare the images (now we dont have to worry about precision, #it is n.n.) assert_array_almost_equal(warped, expected) #verify the is_inverse flag inv = diff_map.inverse() warped = inv.transform_inverse(moving_image, 'linear') assert_array_almost_equal(warped, expected, decimal=5) warped = inv.transform_inverse(moving_image, 'nearest') assert_array_almost_equal(warped, expected) #Now test the inverse functionality diff_map = imwarp.DiffeomorphicMap(2, codomain_shape, codomain_affine, codomain_shape, codomain_affine, domain_shape, domain_affine, None) diff_map.backward = disp for type in [floating, np.float64, np.int64, np.int32]: moving_image = moving_image.astype(type) #warp using linear interpolation warped = diff_map.transform_inverse(moving_image, 'linear') #compare the images (the linear interpolation may introduce slight #precision errors) assert_array_almost_equal(warped, expected, decimal=5) #Now test the nearest neighbor interpolation warped = diff_map.transform_inverse(moving_image, 'nearest') #compare the images (now we don't have to worry about precision, #it is nearest neighbour) assert_array_almost_equal(warped, expected) #Verify that DiffeomorphicMap raises the appropriate exceptions when #the sampling information is undefined diff_map = imwarp.DiffeomorphicMap(2, domain_shape, domain_affine, domain_shape, domain_affine, codomain_shape, codomain_affine, None) diff_map.forward = disp diff_map.domain_shape = None #If we don't provide the sampling info, it should try to use the map's #info, but it's None... assert_raises(ValueError, diff_map.transform, moving_image, 'linear') #Same test for diff_map.transform_inverse diff_map = imwarp.DiffeomorphicMap(2, domain_shape, domain_affine, domain_shape, domain_affine, codomain_shape, codomain_affine, None) diff_map.forward = disp diff_map.codomain_shape = None #If we don't provide the sampling info, it should try to use the map's #info, but it's None... assert_raises(ValueError, diff_map.transform_inverse, moving_image, 'linear') #We must provide, at least, the reference grid shape assert_raises(ValueError, imwarp.DiffeomorphicMap, 2, None)