def id_eulerian(omega, t=1): """ :param omega: discretized domain of the vector field :param t: number of timepoints :return: identity vector field of given domain and timepoints, in Eulerian coordinates. """ d = qr.check_omega(omega) omega = list(omega) v_shape = qr.shape_from_omega_and_timepoints(omega, t=t) id_vf = np.zeros(v_shape) if d == 2: x = range(v_shape[0]) y = range(v_shape[1]) gx, gy = np.meshgrid(x, y, indexing='ij') id_vf[..., 0, :, 0] = np.repeat(gx, t).reshape(omega + [t]) id_vf[..., 0, :, 1] = np.repeat(gy, t).reshape(omega + [t]) elif d == 3: x = range(v_shape[0]) y = range(v_shape[1]) z = range(v_shape[2]) gx, gy, gz = np.meshgrid(x, y, z, indexing='ij') id_vf[..., :, 0] = np.repeat(gx, t).reshape(omega + [t]) id_vf[..., :, 1] = np.repeat(gy, t).reshape(omega + [t]) id_vf[..., :, 2] = np.repeat(gz, t).reshape(omega + [t]) return id_vf
def id_lagrangian(omega, t=1): """ :param omega: discretized domain of the vector field :param t: number of timepoints :return: identity vector field of given domain and timepoints, in Lagrangian coordinates. """ d = qr.check_omega(omega) vf_shape = list(omega) + [1] * (3 - d) + [t, d] return np.zeros(vf_shape)
def id_matrices(omega, t=1): """ From a omega of dimension dim =2,3, it returns the identity field that at each point of the omega has the (row mayor) vectorized identity matrix. :param omega: a squared or cubed omega :param t: timepoint :return: vector field with a vectorised identity matrix at each point. """ d = qr.check_omega(omega) shape = list(omega) + [1] * (4 - d) + [d**2] shape[3] = t flat_id = np.eye(d).reshape(1, d**2) return np.repeat(flat_id, np.prod(list(omega) + [t])).reshape(shape, order='F')
def test_check_omega_ok(): assert qr.check_omega((10, 11, 12)) == 3 assert qr.check_omega((10, 11)) == 2
def test_check_omega_wrong_dimension1(): with assert_raises(IOError): qr.check_omega((10, ))
def test_check_omega_type(): with assert_raises(IOError): qr.check_omega((10, 10, 10.2))
def generate_from_matrix(omega, input_matrix, t=1, structure='algebra'): """ :param omega: domain of the vector field. :param input_matrix: matrix generating the transformation of the vector field representing elements form groups SE(3), SE(2) or algebras so(3) and so(2). :param t: timepoints. :param structure: can be 'algebra' or 'group'. :return: vector field with the given input parameters. """ if t > 1: # TODO raise IndexError('Random generator not defined (yet) for multiple time points') d = qr.check_omega(omega) v_shape = qr.shape_from_omega_and_timepoints(omega, t) vf = np.zeros(v_shape) if structure == 'algebra': pass elif structure == 'group': input_matrix = input_matrix - np.eye(input_matrix.shape[0]) else: raise IOError if d == 2: if not np.alltrue(input_matrix.shape == (3, 3)): raise IOError('Omega dimension not compatible with the matrix dimension') vf = cs.affine_to_homogeneous(gen_id.id_eulerian(omega)) x_intervals, y_intervals = omega for i in range(x_intervals): for j in range(y_intervals): vf[i, j, 0, 0, :] = input_matrix.dot(vf[i, j, 0, 0, :]) vf = cs.homogeneous_to_affine(vf) elif d == 3: # If the matrix provides a 2d rototranslation, we consider the rotation axis perpendicular to the plane z=0. # this must be improved for 3d rotations in the space. x_intervals, y_intervals, z_intervals = omega if np.alltrue(input_matrix.shape == (3, 3)): # Create the slice at the ground of the domain (x,y,z) , z = 0, as a 2d rotation: base_slice = cs.affine_to_homogeneous(gen_id.id_eulerian(list(omega[:2]))) for i in range(x_intervals): for j in range(y_intervals): base_slice[i, j, 0, 0, :] = input_matrix.dot(base_slice[i, j, 0, 0, :]) # Copy the slice at the ground on all the others: for k in range(z_intervals): vf[..., k, 0, :2] = base_slice[..., 0, 0, :2] # If the matrix is 3d the rotation axis is perpendicular to the plane z=0. elif np.alltrue(input_matrix.shape == (4, 4)): vf = cs.affine_to_homogeneous(gen_id.id_eulerian(omega)) for i in range(x_intervals): for j in range(y_intervals): for k in range(z_intervals): vf[i, j, k, 0, :] = input_matrix.dot(vf[i, j, k, 0, :]) vf = cs.homogeneous_to_affine(vf) else: raise IOError('Wrong input matrix shape. Must be 3x3 or 4x4.') return vf
def generate_from_projective_matrix(omega, input_h, t=1, structure='algebra'): """ :param omega: domain of the vector field. :param input_h: matrix representing an element form the homography group. :param t: number of timepoints. :param structure: can be 'algebra' or 'group'. :return: vector field with the given input parameters. """ if t > 1: # TODO raise IndexError('Random generator not defined (yet) for multiple time points') d = qr.check_omega(omega) if structure == 'algebra': if d == 2: idd = gen_id.id_eulerian(omega) vf = gen_id.id_lagrangian(omega) idd = coord.affine_to_homogeneous(idd) x_intervals, y_intervals = omega for i in range(x_intervals): for j in range(y_intervals): vf[i, j, 0, 0, 0] = input_h[0, :].dot(idd[i, j, 0, 0, :]) - i * input_h[2, :].dot(idd[i, j, 0, 0, :]) vf[i, j, 0, 0, 1] = input_h[1, :].dot(idd[i, j, 0, 0, :]) - j * input_h[2, :].dot(idd[i, j, 0, 0, :]) return vf elif d == 3: idd = gen_id.id_eulerian(omega) vf = gen_id.id_lagrangian(omega) idd = coord.affine_to_homogeneous(idd) x_intervals, y_intervals, z_intervals = omega for i in range(x_intervals): for j in range(y_intervals): for k in range(z_intervals): vf[i, j, k, 0, 0] = input_h[0, :].dot(idd[i, j, k, 0, :]) - i * input_h[3, :].dot(idd[i, j, k, 0, :]) vf[i, j, k, 0, 1] = input_h[1, :].dot(idd[i, j, k, 0, :]) - j * input_h[3, :].dot(idd[i, j, k, 0, :]) vf[i, j, k, 0, 2] = input_h[2, :].dot(idd[i, j, k, 0, :]) - k * input_h[3, :].dot(idd[i, j, k, 0, :]) return vf elif structure == 'group': if d == 2: vf = gen_id.id_lagrangian(omega) x_intervals, y_intervals = omega for i in range(x_intervals): for j in range(y_intervals): s = input_h.dot(np.array([i, j, 1]))[:] if abs(s[2]) > 1e-5: # subtract the id to have the result in displacement coordinates vf[i, j, 0, 0, :] = (s[0:2] / float(s[2])) - np.array([i, j]) return vf elif d == 3: vf = gen_id.id_lagrangian(omega) x_intervals, y_intervals, z_intervals = omega for i in range(x_intervals): for j in range(y_intervals): for k in range(z_intervals): s = input_h.dot(np.array([i, j, k, 1]))[:] if abs(s[3]) > 1e-5: vf[i, j, k, 0, :] = (s[0:3] / float(s[3])) - np.array([i, j, k]) return vf else: raise IOError("structure can be only 'algebra' or 'group' corresponding to the algebraic structure.")