Package Transformations: cve.util.geom.transforms
Import instruction :
import cve.trsf3D
About :
Homogeneous Transformation Matrices and Quaternions.
A library for calculating 4x4 matrices for translating, rotating, reflecting, scaling, shearing, projecting, orthogonalizing, and superimposing arrays of 3D homogeneous coordinates as well as for converting between rotation matrices, Euler angles, and quaternions. Also includes an Arcball control object and functions to decompose transformation matrices.
Copyright (c) 2006-2012, Christoph Gohlke
Copyright (c) 2006-2012, The Regents of the University of California Produced at the Laboratory for Fluorescence Dynamics All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
- Neither the name of the copyright holders nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Authors
- Christoph Gohlke http://www.lfd.uci.edu/~gohlke/`__, Laboratory for Fluorescence Dynamics, University of California, Irvine
Version: 2012.01.01
Requirements
CPython 2.7 or 3.2 <http://www.python.org>
__Numpy 1.6 <http://numpy.scipy.org>
__transformations.c 2012.01.01 <http://www.lfd.uci.edu/~gohlke/>
__ (optional implementation of some functions in C)
Notes
The API is not stable yet and is expected to change between revisions.
This Python code is not optimized for speed. Refer to the transformations.c module for a faster implementation of some functions.
Documentation in HTML format can be generated with epydoc.
Matrices (M) can be inverted using numpy.linalg.inv(M), be concatenated using numpy.dot(M0, M1), or transform homogeneous coordinate arrays (v) using numpy.dot(M, v) for shape (4, *) column vectors, respectively numpy.dot(v, M.T) for shape (*, 4) row vectors (“array of points”).
This module follows the “column vectors on the right” and “row major storage” (C contiguous) conventions. The translation components are in the right column of the transformation matrix, i.e. M[:3, 3]. The transpose of the transformation matrices may have to be used to interface with other graphics systems, e.g. with OpenGL’s glMultMatrixd(). See also [16].
Calculations are carried out with numpy.float64 precision.
Vector, point, quaternion, and matrix function arguments are expected to be “array like”, i.e. tuple, list, or numpy arrays.
Return types are numpy arrays unless specified otherwise.
Angles are in radians unless specified otherwise.
Quaternions w+ix+jy+kz are represented as [w, x, y, z].
A triple of Euler angles can be applied/interpreted in 24 ways, which can be specified using a 4 character string or encoded 4-tuple:
- Axes 4-string*: e.g. ‘sxyz’ or ‘ryxy’
- first character : rotations are applied to ‘s’tatic or ‘r’otating frame
- remaining characters : successive rotation axis ‘x’, ‘y’, or ‘z’
- Axes 4-tuple*: e.g. (0, 0, 0, 0) or (1, 1, 1, 1)
- inner axis: code of axis (‘x’:0, ‘y’:1, ‘z’:2) of rightmost matrix.
- parity : even (0) if inner axis ‘x’ is followed by ‘y’, ‘y’ is followed by ‘z’, or ‘z’ is followed by ‘x’. Otherwise odd (1).
- repetition : first and last axis are same (1) or different (0).
- frame : rotations are applied to static (0) or rotating (1) frame.
References
- 1 Matrices and transformations. Ronald Goldman. In “Graphics Gems I”, pp 472-475. Morgan Kaufmann, 1990.
- 2 More matrices and transformations: shear and pseudo-perspective. Ronald Goldman. In “Graphics Gems II”, pp 320-323. Morgan Kaufmann, 1991.
- 3 Decomposing a matrix into simple transformations. Spencer Thomas. In “Graphics Gems II”, pp 320-323. Morgan Kaufmann, 1991.
- 4 Recovering the data from the transformation matrix. Ronald Goldman. In “Graphics Gems II”, pp 324-331. Morgan Kaufmann, 1991.
- 5 Euler angle conversion. Ken Shoemake. In “Graphics Gems IV”, pp 222-229. Morgan Kaufmann, 1994.
- 6 Arcball rotation control. Ken Shoemake. In “Graphics Gems IV”, pp 175-192. Morgan Kaufmann, 1994.
- 7 Representing attitude: Euler angles, unit quaternions, and rotation vectors. James Diebel. 2006.
- 8 A discussion of the solution for the best rotation to relate two sets of vectors. W Kabsch. Acta Cryst. 1978. A34, 827-828.
- 9 Closed-form solution of absolute orientation using unit quaternions.BKP Horn. J Opt Soc Am A. 1987. 4(4):629-642.
- 10 Quaternions. Ken Shoemake. http://www.sfu.ca/~jwa3/cmpt461/files/quatut.pdf
- 11 From quaternion to matrix and back. JMP van Waveren. 2005.http://www.intel.com/cd/ids/developer/asmo-na/eng/293748.htm
- 12 Uniform random rotations. Ken Shoemake. In “Graphics Gems III”, pp 124-132. Morgan Kaufmann, 1992.
- 13 Quaternion in molecular modeling. CFF Karney. J Mol Graph Mod, 25(5):595-604
- 14 New method for extracting the quaternion from a rotation matrix. Itzhack Y Bar-Itzhack, J Guid Contr Dynam. 2000. 23(6): 1085-1087.
- 15 Multiple View Geometry in Computer Vision. Hartley and Zissermann. Cambridge University Press; 2nd Ed. 2004. Chapter 4, Algorithm 4.7, p 130.
- 16 Column Vectors vs. Row Vectors.http://steve.hollasch.net/cgindex/math/matrix/column-vec.html
Examples
alpha, beta, gamma = 0.123, -1.234, 2.345
origin, xaxis, yaxis, zaxis = [0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]
I = identity_matrix()
Rx = rotation_matrix(alpha, xaxis)
Ry = rotation_matrix(beta, yaxis)
Rz = rotation_matrix(gamma, zaxis)
R = concatenate_matrices(Rx, Ry, Rz)
euler = euler_from_matrix(R, 'rxyz')
numpy.allclose([alpha, beta, gamma], euler)
> True
Re = euler_matrix(alpha, beta, gamma, 'rxyz')
is_same_transform(R, Re)
> True
al, be, ga = euler_from_matrix(Re, 'rxyz')
is_same_transform(Re, euler_matrix(al, be, ga, 'rxyz'))
> True
qx = quaternion_about_axis(alpha, xaxis)
qy = quaternion_about_axis(beta, yaxis)
qz = quaternion_about_axis(gamma, zaxis)
q = quaternion_multiply(qx, qy)
q = quaternion_multiply(q, qz)
Rq = quaternion_matrix(q)
is_same_transform(R, Rq)
> True
S = scale_matrix(1.23, origin)
T = translation_matrix([1, 2, 3])
Z = shear_matrix(beta, xaxis, origin, zaxis)
R = random_rotation_matrix(numpy.random.rand(3))
M = concatenate_matrices(T, R, Z, S)
scale, shear, angles, trans, persp = decompose_matrix(M)
numpy.allclose(scale, 1.23)
> True
numpy.allclose(trans, [1, 2, 3])
> True
numpy.allclose(shear, [0, math.tan(beta), 0])
> True
is_same_transform(R, euler_matrix(axes='sxyz', *angles))
> True
M1 = compose_matrix(scale, shear, angles, trans, persp)
is_same_transform(M, M1)
> True
v0, v1 = random_vector(3), random_vector(3)
M = rotation_matrix(angle_between_vectors(v0, v1), vector_product(v0, v1))
v2 = numpy.dot(v0, M[:3,:3].T)
numpy.allclose(unit_vector(v1), unit_vector(v2))
>True
Classes
Class | summury |
---|---|
Arcball | Virtual Trackball Control. |
Functions
Function | summury |
---|---|
**import_module**(module_name, warn=True, prefix=’_py’, ignore=’_’) | Try import all public attributes from module into global namespace. (more…) |
affine_matrix_from_points(v0, v1, shear=True, scale=True, usesvd=True) | Return affine transform matrix to register two point sets. (more…) |
angle_between_vectors(v0, v1, directed=True, axis=0) | Return angle between vectors. (more…) |
arcball_constrain_to_axis(point, axis) | Return sphere point perpendicular to axis. (more…) |
arcball_map_to_sphere(point, center, radius) | Return unit sphere coordinates from window coordinates. (more…) |
arcball_nearest_axis(point, axes) | Return axis, which arc is nearest to point. (more…) |
clip_matrix(left, right, bottom, top, near, far, perspective=False) | Return matrix to obtain normalized device coordinates from frustrum. (more…) |
compose_matrix(scale=None, shear=None, angles=None, translate=None, perspective=None) | Return transformation matrix from sequence of transformations. (more…) |
concatenate_matrices(*matrices) | Return concatenation of series of transformation matrices. (more…) |
decompose_matrix(matrix) | Return sequence of transformations from transformation matrix. (more…) |
euler_from_matrix(matrix, axes=’sxyz’) | Return Euler angles from rotation matrix for specified axis sequence. (more…) |
euler_from_quaternion(quaternion, axes=’sxyz’) | Return Euler angles from quaternion for specified axis sequence. (more…) |
euler_matrix(ai, aj, ak, axes=’sxyz’) | Return homogeneous rotation matrix from Euler angles and axis sequence. (more…) |
identity_matrix() | Return 4x4 identity/unit matrix. (more…) |
inverse_matrix(matrix) | Return inverse of square transformation matrix. (more…) |
is_same_transform(matrix0, matrix1) | Return True if two matrices perform same transformation. (more…) |
orthogonalization_matrix(lengths, angles) | Return orthogonalization matrix for crystallographic cell coordinates. (more…) |
projection_from_matrix(matrix, pseudo=False) | Return projection plane and perspective point from projection matrix. (more…) |
projection_matrix(point, normal, direction=None, perspective=None, pseudo=False) | Return matrix to project onto plane defined by point and normal. (more…) |
quaternion_about_axis(angle, axis) | Return quaternion for rotation about axis. (more…) |
quaternion_conjugate(quaternion) | Return conjugate of quaternion. (more…) |
quaternion_from_euler(ai, aj, ak, axes=’sxyz’) | Return quaternion from Euler angles and axis sequence. (more…) |
quaternion_from_matrix(matrix, isprecise=False) | Return quaternion from rotation matrix. (more…) |
quaternion_from_matrix1(matrix) | |
quaternion_imag(quaternion) | Return imaginary part of quaternion. (more…) |
quaternion_inverse(quaternion) | Return inverse of quaternion. (more…) |
quaternion_matrix(quaternion) | Return homogeneous rotation matrix from quaternion. (more…) |
quaternion_matrix1(qx, qy, qz, qw) | This function was rebuilt since the trsf3D function of cve.util seems fake (more…) |
quaternion_multiply(quaternion1, quaternion0) | Return multiplication of two quaternions. (more…) |
quaternion_real(quaternion) | Return real part of quaternion. (more…) |
quaternion_slerp(quat0, quat1, fraction, spin=0, shortestpath=True) | Return spherical linear interpolation between two quaternions. (more…) |
random_quaternion(rand=None) | Return uniform random unit quaternion. (more…) |
random_rotation_matrix(rand=None) | Return uniform random rotation matrix. (more…) |
random_vector(size) | Return array of random doubles in the half-open interval [0.0, 1.0). (more…) |
reflection_from_matrix(matrix) | Return mirror plane point and normal vector from reflection matrix. (more…) |
reflection_matrix(point, normal) | Return matrix to mirror at plane defined by point and normal vector. (more…) |
rotation_from_matrix(matrix) | Return rotation angle and axis from rotation matrix. (more…) |
rotation_matrix(angle, direction, point=None) | Return matrix to rotate about axis defined by point and direction. (more…) |
rotation_matrix_from_cos_sin(cosa, sina, direction, point=None) | Return matrix to rotate about axis defined by point and direction. (more…) |
scale_from_matrix(matrix) | Return scaling factor, origin and direction from scaling matrix. (more…) |
scale_matrix(factor, origin=None, direction=None) | Return matrix to scale by factor around origin in direction. (more…) |
shear_from_matrix(matrix) | Return shear angle, direction and plane from shear matrix. (more…) |
shear_matrix(angle, direction, point, normal) | Return matrix to shear by angle along direction vector on shear plane. (more…) |
superimposition_matrix(v0, v1, scale=False, usesvd=True) | Return matrix to transform given 3D point set into second point set. (more…) |
translation_from_matrix(matrix) | Return translation vector from translation matrix. (more…) |
translation_matrix(direction) | Return matrix to translate by direction vector. (more…) |
unit_vector(data, axis=None, out=None) | Return ndarray normalized by length, i.e. eucledian norm, along axis. (more…) |
vector_norm(data, axis=None, out=None) | Return length, i.e. eucledian norm, of ndarray along axis. (more…) |
vector_product(v0, v1, axis=0) | Return vector perpendicular to vectors. (more…) |
Functions details
_import_module
def _import_module(module_name, warn=True, prefix='_py_', ignore='_')
Try import all public attributes from module into global namespace.
Existing attributes with name clashes are renamed with prefix. Attributes starting with underscore are ignored by default.
Return True on successful import.
affine_matrix_from_points
def affine_matrix_from_points(v0, v1, shear=True, scale=True, usesvd=True)
Return affine transform matrix to register two point sets.
v0 and v1 are shape (ndims, *) arrays of at least ndims non-homogeneous coordinates, where ndims is the dimensionality of the coordinate space.
If shear is False, a similarity transformation matrix is returned. If also scale is False, a rigid/Eucledian transformation matrix is returned.
By default the algorithm by Hartley and Zissermann [15] is used. If usesvd is True, similarity and Eucledian transformation matrices are calculated by minimizing the weighted sum of squared deviations (RMSD) according to the algorithm by Kabsch [8]. Otherwise, and if ndims is 3, the quaternion based algorithm by Horn [9] is used, which is slower when using this Python implementation.
The returned matrix performs rotation, translation and uniform scaling (if specified).
v0 = [[0, 1031, 1031, 0], [0, 0, 1600, 1600]] v1 = [[675, 826, 826, 677], [55, 52, 281, 277]] affine_matrix_from_points(v0, v1) array([[ 0.14549, 0.00062, 675.50008], [ 0.00048, 0.14094, 53.24971], [ 0. , 0. , 1. ]]) T = translation_matrix(numpy.random.random(3)-0.5) R = random_rotation_matrix(numpy.random.random(3)) S = scale_matrix(random.random()) M = concatenate_matrices(T, R, S) v0 = (numpy.random.rand(4, 100) - 0.5) * 20 v0[3] = 1 v1 = numpy.dot(M, v0) v0[:3] += numpy.random.normal(0, 1e-8, 300).reshape(3, -1) M = affine_matrix_from_points(v0[:3], v1[:3]) numpy.allclose(v1, numpy.dot(M, v0)) True
More examples in superimposition_matrix()
angle_between_vectors
def angle_between_vectors(v0, v1, directed=True, axis=0)
Return angle between vectors.
If directed is False, the input vectors are interpreted as undirected axes, i.e. the maximum angle is pi/2.
a = angle_between_vectors([1, -2, 3], [-1, 2, -3]) numpy.allclose(a, math.pi) True a = angle_between_vectors([1, -2, 3], [-1, 2, -3], directed=False) numpy.allclose(a, 0) True v0 = [[2, 0, 0, 2], [0, 2, 0, 2], [0, 0, 2, 2]] v1 = [[3], [0], [0]] a = angle_between_vectors(v0, v1) numpy.allclose(a, [0, 1.5708, 1.5708, 0.95532]) True v0 = [[2, 0, 0], [2, 0, 0], [0, 2, 0], [2, 0, 0]] v1 = [[0, 3, 0], [0, 0, 3], [0, 0, 3], [3, 3, 3]] a = angle_between_vectors(v0, v1, axis=1) numpy.allclose(a, [1.5708, 1.5708, 1.5708, 0.95532]) True
arcball_constrain_to_axis
def arcball_constrain_to_axis(point, axis)
Return sphere point perpendicular to axis.
arcball_map_to_sphere
def arcball_map_to_sphere(point, center, radius)
Return unit sphere coordinates from window coordinates.
arcball_nearest_axis
def arcball_nearest_axis(point, axes)
Return axis, which arc is nearest to point.
clip_matrix
def clip_matrix(left, right, bottom, top, near, far, perspective=False)
Return matrix to obtain normalized device coordinates from frustrum.
The frustrum bounds are axis-aligned along x (left, right), y (bottom, top) and z (near, far).
Normalized device coordinates are in range [-1, 1] if coordinates are inside the frustrum.
If perspective is True the frustrum is a truncated pyramid with the perspective point at origin and direction along z axis, otherwise an orthographic canonical view volume (a box).
Homogeneous coordinates transformed by the perspective clip matrix need to be dehomogenized (divided by w coordinate).
frustrum = numpy.random.rand(6) frustrum[1] += frustrum[0] frustrum[3] += frustrum[2] frustrum[5] += frustrum[4] M = clip_matrix(perspective=False, *frustrum) numpy.dot(M, [frustrum[0], frustrum[2], frustrum[4], 1]) array([-1., -1., -1., 1.]) numpy.dot(M, [frustrum[1], frustrum[3], frustrum[5], 1]) array([ 1., 1., 1., 1.]) M = clip_matrix(perspective=True, *frustrum) v = numpy.dot(M, [frustrum[0], frustrum[2], frustrum[4], 1]) v / v[3] array([-1., -1., -1., 1.]) v = numpy.dot(M, [frustrum[1], frustrum[3], frustrum[4], 1]) v / v[3] array([ 1., 1., -1., 1.])
compose_matrix
def compose_matrix(scale=None, shear=None, angles=None, translate=None, perspective=None)
Return transformation matrix from sequence of transformations.
This is the inverse of the decompose_matrix function.
Sequence of transformations: scale : vector of 3 scaling factors shear : list of shear factors for x-y, x-z, y-z axes angles : list of Euler angles about static x, y, z axes translate : translation vector along x, y, z axes perspective : perspective partition of matrix
scale = numpy.random.random(3) - 0.5 shear = numpy.random.random(3) - 0.5 angles = (numpy.random.random(3) - 0.5) * (2math.pi) trans = numpy.random.random(3) - 0.5 persp = numpy.random.random(4) - 0.5 M0 = compose_matrix(scale, shear, angles, trans, persp) result = decompose_matrix(M0) M1 = compose_matrix(result) is_same_transform(M0, M1) True
concatenate_matrices
def concatenate_matrices(*matrices)
Return concatenation of series of transformation matrices.
M = numpy.random.rand(16).reshape((4, 4)) - 0.5 numpy.allclose(M, concatenate_matrices(M)) True numpy.allclose(numpy.dot(M, M.T), concatenate_matrices(M, M.T)) True
decompose_matrix
def decompose_matrix(matrix)
Return sequence of transformations from transformation matrix.
matrix : array_like Non-degenerative homogeneous transformation matrix
Return tuple of: scale : vector of 3 scaling factors shear : list of shear factors for x-y, x-z, y-z axes angles : list of Euler angles about static x, y, z axes translate : translation vector along x, y, z axes perspective : perspective partition of matrix
Raise ValueError if matrix is of wrong type or degenerative.
T0 = translation_matrix([1, 2, 3]) scale, shear, angles, trans, persp = decompose_matrix(T0) T1 = translation_matrix(trans) numpy.allclose(T0, T1) True S = scale_matrix(0.123) scale, shear, angles, trans, persp = decompose_matrix(S) scale[0] 0.123 R0 = euler_matrix(1, 2, 3) scale, shear, angles, trans, persp = decompose_matrix(R0) R1 = euler_matrix(*angles) numpy.allclose(R0, R1) True
euler_from_matrix
def euler_from_matrix(matrix, axes='sxyz')
Return Euler angles from rotation matrix for specified axis sequence.
axes : One of 24 axis sequences as string or encoded tuple
Note that many Euler angle triplets can describe one matrix.
R0 = euler_matrix(1, 2, 3, ‘syxz’) al, be, ga = euler_from_matrix(R0, ‘syxz’) R1 = euler_matrix(al, be, ga, ‘syxz’) numpy.allclose(R0, R1) True angles = (4*math.pi) * (numpy.random.random(3) - 0.5) for axes in _AXES2TUPLE.keys(): … R0 = euler_matrix(axes=axes, *angles) … R1 = euler_matrix(axes=axes, *euler_from_matrix(R0, axes)) … if not numpy.allclose(R0, R1): print(axes, “failed”)
euler_from_quaternion
def euler_from_quaternion(quaternion, axes='sxyz')
Return Euler angles from quaternion for specified axis sequence.
angles = euler_from_quaternion([0.99810947, 0.06146124, 0, 0]) numpy.allclose(angles, [0.123, 0, 0]) True
euler_matrix
def euler_matrix(ai, aj, ak, axes='sxyz')
Return homogeneous rotation matrix from Euler angles and axis sequence.
ai, aj, ak : Euler’s roll, pitch and yaw angles axes : One of 24 axis sequences as string or encoded tuple
R = euler_matrix(1, 2, 3, ‘syxz’) numpy.allclose(numpy.sum(R[0]), -1.34786452) True R = euler_matrix(1, 2, 3, (0, 1, 0, 1)) numpy.allclose(numpy.sum(R[0]), -0.383436184) True ai, aj, ak = (4*math.pi) * (numpy.random.random(3) - 0.5) for axes in _AXES2TUPLE.keys(): … R = euler_matrix(ai, aj, ak, axes) for axes in _TUPLE2AXES.keys(): … R = euler_matrix(ai, aj, ak, axes)
identity_matrix
def identity_matrix()
Return 4x4 identity/unit matrix.
- ← : a numpy identity matrix
Example
I = identity_matrix()
numpy.allclose(I, numpy.dot(I, I))
>True
numpy.sum(I), numpy.trace(I)
>(4.0, 4.0)
numpy.allclose(I, numpy.identity(4))
>True
inverse_matrix
def inverse_matrix(matrix)
Return inverse of square transformation matrix.
M0 = random_rotation_matrix() M1 = inverse_matrix(M0.T) numpy.allclose(M1, numpy.linalg.inv(M0.T)) True for size in range(1, 7): … M0 = numpy.random.rand(size, size) … M1 = inverse_matrix(M0) … if not numpy.allclose(M1, numpy.linalg.inv(M0)): print(size)
is_same_transform
def is_same_transform(matrix0, matrix1)
Return True if two matrices perform same transformation.
is_same_transform(numpy.identity(4), numpy.identity(4)) True is_same_transform(numpy.identity(4), random_rotation_matrix()) False
orthogonalization_matrix
def orthogonalization_matrix(lengths, angles)
Return orthogonalization matrix for crystallographic cell coordinates.
Angles are expected in degrees.
The de-orthogonalization matrix is the inverse.
O = orthogonalization_matrix([10, 10, 10], [90, 90, 90]) numpy.allclose(O[:3, :3], numpy.identity(3, float) * 10) True O = orthogonalization_matrix([9.8, 12.0, 15.5], [87.2, 80.7, 69.7]) numpy.allclose(numpy.sum(O), 43.063229) True
projection_from_matrix
def projection_from_matrix(matrix, pseudo=False)
Return projection plane and perspective point from projection matrix.
Return values are same as arguments for projection_matrix function: point, normal, direction, perspective, and pseudo.
point = numpy.random.random(3) - 0.5 normal = numpy.random.random(3) - 0.5 direct = numpy.random.random(3) - 0.5 persp = numpy.random.random(3) - 0.5 P0 = projection_matrix(point, normal) result = projection_from_matrix(P0) P1 = projection_matrix(result) is_same_transform(P0, P1) True P0 = projection_matrix(point, normal, direct) result = projection_from_matrix(P0) P1 = projection_matrix(result) is_same_transform(P0, P1) True P0 = projection_matrix(point, normal, perspective=persp, pseudo=False) result = projection_from_matrix(P0, pseudo=False) P1 = projection_matrix(result) is_same_transform(P0, P1) True P0 = projection_matrix(point, normal, perspective=persp, pseudo=True) result = projection_from_matrix(P0, pseudo=True) P1 = projection_matrix(result) is_same_transform(P0, P1) True
projection_matrix
def projection_matrix(point, normal, direction=None, perspective=None, pseudo=False)
Return matrix to project onto plane defined by point and normal.
Using either perspective point, projection direction, or none of both.
If pseudo is True, perspective projections will preserve relative depth such that Perspective = dot(Orthogonal, PseudoPerspective).
P = projection_matrix([0, 0, 0], [1, 0, 0]) numpy.allclose(P[1:, 1:], numpy.identity(4)[1:, 1:]) True point = numpy.random.random(3) - 0.5 normal = numpy.random.random(3) - 0.5 direct = numpy.random.random(3) - 0.5 persp = numpy.random.random(3) - 0.5 P0 = projection_matrix(point, normal) P1 = projection_matrix(point, normal, direction=direct) P2 = projection_matrix(point, normal, perspective=persp) P3 = projection_matrix(point, normal, perspective=persp, pseudo=True) is_same_transform(P2, numpy.dot(P0, P3)) True P = projection_matrix([3, 0, 0], [1, 1, 0], [1, 0, 0]) v0 = (numpy.random.rand(4, 5) - 0.5) * 20 v0[3] = 1 v1 = numpy.dot(P, v0) numpy.allclose(v1[1], v0[1]) True numpy.allclose(v1[0], 3-v1[1]) True
quaternion_about_axis
def quaternion_about_axis(angle, axis)
Return quaternion for rotation about axis.
q = quaternion_about_axis(0.123, [1, 0, 0]) numpy.allclose(q, [0.99810947, 0.06146124, 0, 0]) True
quaternion_conjugate
def quaternion_conjugate(quaternion)
Return conjugate of quaternion.
q0 = random_quaternion() q1 = quaternion_conjugate(q0) q1[0] == q0[0] and all(q1[1:] == -q0[1:]) True
quaternion_from_euler
def quaternion_from_euler(ai, aj, ak, axes='sxyz')
Return quaternion from Euler angles and axis sequence.
ai, aj, ak : Euler’s roll, pitch and yaw angles axes : One of 24 axis sequences as string or encoded tuple
q = quaternion_from_euler(1, 2, 3, ‘ryxz’) numpy.allclose(q, [0.435953, 0.310622, -0.718287, 0.444435]) True
quaternion_from_matrix
def quaternion_from_matrix(matrix, isprecise=False)
Return quaternion from rotation matrix.
If isprecise is True, the input matrix is assumed to be a precise rotation matrix and a faster algorithm is used.
q = quaternion_from_matrix(numpy.identity(4), True) numpy.allclose(q, [1, 0, 0, 0]) True q = quaternion_from_matrix(numpy.diag([1, -1, -1, 1])) numpy.allclose(q, [0, 1, 0, 0]) or numpy.allclose(q, [0, -1, 0, 0]) True R = rotation_matrix(0.123, (1, 2, 3)) q = quaternion_from_matrix(R, True) numpy.allclose(q, [0.9981095, 0.0164262, 0.0328524, 0.0492786]) True R = [[-0.545, 0.797, 0.260, 0], [0.733, 0.603, -0.313, 0], … [-0.407, 0.021, -0.913, 0], [0, 0, 0, 1]] q = quaternion_from_matrix(R) numpy.allclose(q, [0.19069, 0.43736, 0.87485, -0.083611]) True R = [[0.395, 0.362, 0.843, 0], [-0.626, 0.796, -0.056, 0], … [-0.677, -0.498, 0.529, 0], [0, 0, 0, 1]] q = quaternion_from_matrix(R) numpy.allclose(q, [0.82336615, -0.13610694, 0.46344705, -0.29792603]) True R = random_rotation_matrix() q = quaternion_from_matrix(R) is_same_transform(R, quaternion_matrix(q)) True
quaternion_imag
def quaternion_imag(quaternion)
Return imaginary part of quaternion.
quaternion_imag([3, 0, 1, 2]) array([ 0., 1., 2.])
quaternion_inverse
def quaternion_inverse(quaternion)
Return inverse of quaternion.
q0 = random_quaternion() q1 = quaternion_inverse(q0) numpy.allclose(quaternion_multiply(q0, q1), [1, 0, 0, 0]) True
quaternion_matrix
def quaternion_matrix(quaternion)
Return homogeneous rotation matrix from quaternion.
M = quaternion_matrix([0.99810947, 0.06146124, 0, 0]) numpy.allclose(M, rotation_matrix(0.123, [1, 0, 0])) True M = quaternion_matrix([1, 0, 0, 0]) numpy.allclose(M, numpy.identity(4)) True M = quaternion_matrix([0, 1, 0, 0]) numpy.allclose(M, numpy.diag([1, -1, -1, 1])) True
quaternion_matrix1
def quaternion_matrix1(qx, qy, qz, qw)
This function was rebuilt since the trsf3D function of cve.util seems fake This new one works very fine with optitrack feedback
- qx,qy,qz,qw : quaternion parameters
- returns a rotation matrix
quaternion_multiply
def quaternion_multiply(quaternion1, quaternion0)
Return multiplication of two quaternions.
q = quaternion_multiply([4, 1, -2, 3], [8, -5, 6, 7]) numpy.allclose(q, [28, -44, -14, 48]) True
quaternion_real
def quaternion_real(quaternion)
Return real part of quaternion.
quaternion_real([3, 0, 1, 2]) 3.0
quaternion_slerp
def quaternion_slerp(quat0, quat1, fraction, spin=0, shortestpath=True)
Return spherical linear interpolation between two quaternions.
q0 = random_quaternion() q1 = random_quaternion() q = quaternion_slerp(q0, q1, 0) numpy.allclose(q, q0) True q = quaternion_slerp(q0, q1, 1, 1) numpy.allclose(q, q1) True q = quaternion_slerp(q0, q1, 0.5) angle = math.acos(numpy.dot(q0, q)) numpy.allclose(2, math.acos(numpy.dot(q0, q1)) / angle) or numpy.allclose(2, math.acos(-numpy.dot(q0, q1)) / angle) True
random_quaternion
def random_quaternion(rand=None)
Return uniform random unit quaternion.
rand: array like or None Three independent random variables that are uniformly distributed between 0 and 1.
q = random_quaternion() numpy.allclose(1, vector_norm(q)) True q = random_quaternion(numpy.random.random(3)) len(q.shape), q.shape[0]==4 (1, True)
random_rotation_matrix
def random_rotation_matrix(rand=None)
Return uniform random rotation matrix.
rand: array like Three independent random variables that are uniformly distributed between 0 and 1 for each returned quaternion.
R = random_rotation_matrix() numpy.allclose(numpy.dot(R.T, R), numpy.identity(4)) True
random_vector
def random_vector(size)
Return array of random doubles in the half-open interval [0.0, 1.0).
v = random_vector(10000) numpy.all(v >= 0) and numpy.all(v < 1) True v0 = random_vector(10) v1 = random_vector(10) numpy.any(v0 == v1) False
reflection_from_matrix
def reflection_from_matrix(matrix)
Return mirror plane point and normal vector from reflection matrix.
Example
v0 = numpy.random.random(3) - 0.5
v1 = numpy.random.random(3) - 0.5
M0 = reflection_matrix(v0, v1)
point, normal = reflection_from_matrix(M0)
M1 = reflection_matrix(point, normal)
is_same_transform(M0, M1)
>True
reflection_matrix
def reflection_matrix(point, normal)
Return matrix to mirror at plane defined by point and normal vector.
Example
v0 = numpy.random.random(4) - 0.5
v0[3] = 1.
v1 = numpy.random.random(3) - 0.5
R = reflection_matrix(v0, v1)
numpy.allclose(2, numpy.trace(R))
> True
numpy.allclose(v0, numpy.dot(R, v0))
> True
v2 = v0.copy()
v2[:3] += v1
v3 = v0.copy()
v2[:3] -= v1
numpy.allclose(v2, numpy.dot(R, v3))
>True
rotation_from_matrix
def rotation_from_matrix(matrix)
Return rotation angle and axis from rotation matrix.
Extract the rotation matrix from a 4x4 transform
- →: matrix the input transformation matrix
- ← angle, direction, point
angle = (random.random() - 0.5) * (2*math.pi)
direc = numpy.random.random(3) - 0.5
point = numpy.random.random(3) - 0.5
R0 = rotation_matrix(angle, direc, point)
angle, direc, point = rotation_from_matrix(R0)
R1 = rotation_matrix(angle, direc, point)
is_same_transform(R0, R1)
> True
rotation_matrix
def rotation_matrix(angle, direction, point=None)
Return matrix to rotate about axis defined by point and direction.
Example
R = rotation_matrix(math.pi/2, [0, 0, 1], [1, 0, 0])
numpy.allclose(numpy.dot(R, [0, 0, 0, 1]), [1, -1, 0, 1])
> True
angle = (random.random() - 0.5) * (2*math.pi)
direc = numpy.random.random(3) - 0.5
point = numpy.random.random(3) - 0.5
R0 = rotation_matrix(angle, direc, point)
R1 = rotation_matrix(angle-2*math.pi, direc, point)
is_same_transform(R0, R1)
> True
R0 = rotation_matrix(angle, direc, point)
R1 = rotation_matrix(-angle, -direc, point)
is_same_transform(R0, R1)
> True
I = numpy.identity(4, numpy.float64)
numpy.allclose(I, rotation_matrix(math.pi*2, direc))
> True
numpy.allclose(2, numpy.trace(rotation_matrix(math.pi/2,
... direc, point)))
> True
rotation_matrix_from_cos_sin
def rotation_matrix_from_cos_sin(cosa, sina, direction, point=None)
Return matrix to rotate about axis defined by point and direction.
- →: cosa : the cosinus of the angle
- →: sina : the sinus of the angle
- →: direction : a 3-tuple fixing the direction : it is automatically normalized
- →: point : if None the line pass by the point (0,0,0) else it is a point : the ligne passes through this point.
- ← a numpyt 4x4 transformation matrix
scale_from_matrix
def scale_from_matrix(matrix)
Return scaling factor, origin and direction from scaling matrix.
factor = random.random() * 10 - 5 origin = numpy.random.random(3) - 0.5 direct = numpy.random.random(3) - 0.5 S0 = scale_matrix(factor, origin) factor, origin, direction = scale_from_matrix(S0) S1 = scale_matrix(factor, origin, direction) is_same_transform(S0, S1) True S0 = scale_matrix(factor, origin, direct) factor, origin, direction = scale_from_matrix(S0) S1 = scale_matrix(factor, origin, direction) is_same_transform(S0, S1) True
scale_matrix
def scale_matrix(factor, origin=None, direction=None)
Return matrix to scale by factor around origin in direction.
Use factor -1 for point symmetry.
v = (numpy.random.rand(4, 5) - 0.5) * 20 v[3] = 1 S = scale_matrix(-1.234) numpy.allclose(numpy.dot(S, v)[:3], -1.234*v[:3]) True factor = random.random() * 10 - 5 origin = numpy.random.random(3) - 0.5 direct = numpy.random.random(3) - 0.5 S = scale_matrix(factor, origin) S = scale_matrix(factor, origin, direct)
shear_from_matrix
def shear_from_matrix(matrix)
Return shear angle, direction and plane from shear matrix.
angle = (random.random() - 0.5) * 4*math.pi direct = numpy.random.random(3) - 0.5 point = numpy.random.random(3) - 0.5 normal = numpy.cross(direct, numpy.random.random(3)) S0 = shear_matrix(angle, direct, point, normal) angle, direct, point, normal = shear_from_matrix(S0) S1 = shear_matrix(angle, direct, point, normal) is_same_transform(S0, S1) True
shear_matrix
def shear_matrix(angle, direction, point, normal)
Return matrix to shear by angle along direction vector on shear plane.
The shear plane is defined by a point and normal vector. The direction vector must be orthogonal to the plane’s normal vector.
A point P is transformed by the shear matrix into P” such that the vector P-P” is parallel to the direction vector and its extent is given by the angle of P-P’-P”, where P’ is the orthogonal projection of P onto the shear plane.
angle = (random.random() - 0.5) * 4*math.pi direct = numpy.random.random(3) - 0.5 point = numpy.random.random(3) - 0.5 normal = numpy.cross(direct, numpy.random.random(3)) S = shear_matrix(angle, direct, point, normal) numpy.allclose(1, numpy.linalg.det(S)) True
superimposition_matrix
def superimposition_matrix(v0, v1, scale=False, usesvd=True)
Return matrix to transform given 3D point set into second point set.
v0 and v1 are shape (3, *) or (4, *) arrays of at least 3 points.
The parameters scale and usesvd are explained in the more general affine_matrix_from_points function.
The returned matrix is a similarity or Eucledian transformation matrix. This function has a fast C implementation in transformations.c.
v0 = numpy.random.rand(3, 10) M = superimposition_matrix(v0, v0) numpy.allclose(M, numpy.identity(4)) True R = random_rotation_matrix(numpy.random.random(3)) v0 = [[1,0,0], [0,1,0], [0,0,1], [1,1,1]] v1 = numpy.dot(R, v0) M = superimposition_matrix(v0, v1) numpy.allclose(v1, numpy.dot(M, v0)) True v0 = (numpy.random.rand(4, 100) - 0.5) * 20 v0[3] = 1 v1 = numpy.dot(R, v0) M = superimposition_matrix(v0, v1) numpy.allclose(v1, numpy.dot(M, v0)) True S = scale_matrix(random.random()) T = translation_matrix(numpy.random.random(3)-0.5) M = concatenate_matrices(T, R, S) v1 = numpy.dot(M, v0) v0[:3] += numpy.random.normal(0, 1e-9, 300).reshape(3, -1) M = superimposition_matrix(v0, v1, scale=True) numpy.allclose(v1, numpy.dot(M, v0)) True M = superimposition_matrix(v0, v1, scale=True, usesvd=False) numpy.allclose(v1, numpy.dot(M, v0)) True v = numpy.empty((4, 100, 3)) v[:, :, 0] = v0 M = superimposition_matrix(v0, v1, scale=True, usesvd=False) numpy.allclose(v1, numpy.dot(M, v[:, :, 0])) True
translation_from_matrix
def translation_from_matrix(matrix)
Return translation vector from translation matrix.
Example
v0 = numpy.random.random(3) - 0.5
v1 = translation_from_matrix(translation_matrix(v0))
numpy.allclose(v0, v1)
>True
translation_matrix
def translation_matrix(direction)
Return matrix to translate by direction vector.
Example
>>> v = numpy.random.random(3) - 0.5
>>> numpy.allclose(v, translation_matrix(v)[:3, 3])
True
unit_vector
def unit_vector(data, axis=None, out=None)
Return ndarray normalized by length, i.e. eucledian norm, along axis.
v0 = numpy.random.random(3) v1 = unit_vector(v0) numpy.allclose(v1, v0 / numpy.linalg.norm(v0)) True v0 = numpy.random.rand(5, 4, 3) v1 = unit_vector(v0, axis=-1) v2 = v0 / numpy.expand_dims(numpy.sqrt(numpy.sum(v0v0, axis=2)), 2) numpy.allclose(v1, v2) True v1 = unit_vector(v0, axis=1) v2 = v0 / numpy.expand_dims(numpy.sqrt(numpy.sum(v0v0, axis=1)), 1) numpy.allclose(v1, v2) True v1 = numpy.empty((5, 4, 3)) unit_vector(v0, axis=1, out=v1) numpy.allclose(v1, v2) True list(unit_vector([])) [] list(unit_vector([1])) [1.0]
vector_norm
def vector_norm(data, axis=None, out=None)
Return length, i.e. eucledian norm, of ndarray along axis.
v = numpy.random.random(3) n = vector_norm(v) numpy.allclose(n, numpy.linalg.norm(v)) True v = numpy.random.rand(6, 5, 3) n = vector_norm(v, axis=-1) numpy.allclose(n, numpy.sqrt(numpy.sum(vv, axis=2))) True n = vector_norm(v, axis=1) numpy.allclose(n, numpy.sqrt(numpy.sum(vv, axis=1))) True v = numpy.random.rand(5, 4, 3) n = numpy.empty((5, 3)) vector_norm(v, axis=1, out=n) numpy.allclose(n, numpy.sqrt(numpy.sum(v*v, axis=1))) True vector_norm([]) 0.0 vector_norm([1]) 1.0
vector_product
def vector_product(v0, v1, axis=0)
Return vector perpendicular to vectors.
v = vector_product([2, 0, 0], [0, 3, 0]) numpy.allclose(v, [0, 0, 6]) True v0 = [[2, 0, 0, 2], [0, 2, 0, 2], [0, 0, 2, 2]] v1 = [[3], [0], [0]] v = vector_product(v0, v1) numpy.allclose(v, [[0, 0, 0, 0], [0, 0, 6, 6], [0, -6, 0, -6]]) True v0 = [[2, 0, 0], [2, 0, 0], [0, 2, 0], [2, 0, 0]] v1 = [[0, 3, 0], [0, 0, 3], [0, 0, 3], [3, 3, 3]] v = vector_product(v0, v1, axis=1) numpy.allclose(v, [[0, 0, 6], [0, -6, 0], [6, 0, 0], [0, -6, 6]]) True