Module src.util.math_utils
Math utils.
Collection of mathematical functions used in various parts of this project.
Functions
def angle_between_vectors(u: numpy.ndarray, v: numpy.ndarray) ‑> float-
Finds the angle between two vectors.
Args
u- An arbitrary dimensional vector.
v- An arbitrary dimensional vector.
Returns
Angle between the vectors in radians, domain- [0, pi]
def signed_angle(u: numpy.ndarray, v: numpy.ndarray, n: numpy.ndarray) ‑> float-
Signed angle theta between vectors u and v given normal vector n.
\sin\theta={(\boldsymbol{n}\times\boldsymbol{u})\cdot\boldsymbol{v}\over |u||v|}. \theta = \begin{cases} \arccos{\frac{u\cdot v}{|u||v|}}, & \text{if $\sin\theta\ge0$;}\\ 2\pi-\arccos{\frac{u \cdot v}{|u||v|}}, & \text{if $\sin\theta<0$.}\\ \end{cases}
Args
u- An arbitrary dimensional vector.
v- An arbitrary dimensional vector.
n- Plane normal for vectors u & v.
Returns
Signed angle in radians between the two vectors u and v, given the orientational normal vector n. Domain [-pi, pi].
def to_unit_vector(v: numpy.ndarray) ‑> numpy.ndarray-
Calculate unit vector corresponding to input vector.
Does not support zero vector.
Args
v- An arbitrary dimensional vector.
Returns
The unit vector corresponding to the vector v.
Raises
AssertionError- If the given vector is a zero vector.
def transform_length(v: numpy.ndarray, new_length: float) ‑> numpy.ndarray-
Calculate a new vector parallell to the vector v, with length new_length.
Args
v- An arbitrary dimensional vector. Zero vector not supported.
new_length- The desired length for the returned vector. Must be non-negative.
Returns
A vector of same shape and direction as v, with magnitude equaling new length.
Raises
AssertionError- If the given v is a zero vector.
def landmark_to_vector(lm: mediapipe.framework.formats.landmark_pb2.NormalizedLandmark) ‑> numpy.ndarray-
Convert landmark to a vector
Args
lm- A normalized landmark.
Returns
A 3d-vector corresponding to the input landmark.
def landmarks_to_vectors(lms: Iterable[mediapipe.framework.formats.landmark_pb2.NormalizedLandmark]) ‑> numpy.ndarray-
Convert an iterable of landmarks to an array of corresponding vectors.
Args
lms- An iterable of normalized landmarks.
Returns
An array of vectors corresponding to the landmarks in lms.
def line_intersection(a1: numpy.ndarray, a2: numpy.ndarray, b1: numpy.ndarray, b2: numpy.ndarray) ‑> numpy.ndarray-
Intersection between two lines from four points.
Constructs two lines in the xy-plane from a1 -> a2, b1 -> b2, and finds the intersection between these two.
Args
a1, a2: Two corresponding points as np.arrays of length 2, forms the first line. b1, b2: Two corresponding points as np.arrays of length 2, forms the second line.
Returns
The intersection point between the constructed lines as a np.array of length 2. Parallel lines generates the return value
np.array([np.nan, np.nan])(see below).Raises
UserWarning- For a set of points that gives parallel lines (no intersection to be found).
def normalized_to_pixel_coordinates(normalized_x: float, normalized_y: float, width: int, height: int) ‑> Union[NoneType, Tuple[int, int]]-
Converts a normalized value pair to pixel coordinates.
Args
normalized_x- x-coordinate, must be in domain [0, 1]
normalized_y- y-coordinate, must be in domain [0, 1]
width- Width of image.
height- Height of image.
Returns
An (x, y) tuple of pixel coordinates. Note that the max for the return values is one less than width / height.
def get_extreme_points(points: Iterable[numpy.ndarray], width: int, height: int) ‑> Tuple[Tuple[int, int], Tuple[int, int]]-
Get corners of provided points.
Given an iterable of normalized points together with image width and height, returns pixel coordinates of the outer points.
Args
points- Normalized points of with x, y coordinates at 0th and 1st index respectively.
width- Width of the image that the return value should be fitted to.
height- Height of the image that the return values hould be fitted to.
Returns
A tupleoftwo tuples- (top_left, bot_right) = ((x_min, y_min), (x_max, y_max)).
These corners gives a bounding box surrounding the provided points. Note that origin is located at top left.
def centroid(triangle: Tuple[numpy.ndarray, numpy.ndarray, numpy.ndarray]) ‑> numpy.ndarray-
Calculate centroid of a triangle.
The centroid of a triangle is the point of intersection of its medians.
Args
triangle- Three-tuple of the triangle corners as numpy arrays. The arrays must have the same length >= 2
Returns
Centroid of the triangle as a np.ndarray.
def cube_root(n: Union[float, complex]) ‑> Union[float, complex]-
Computes cubic root of a real/complex number while maintaining its sign
When raising negative numbers to fractional powers, which in essence is a multivalued function, python favors the priciple solution (that is the solution with the largest real part), which results in complex results for negative real inputs.
This is not what we want in this case though, we want the cube root of a real to stay real. Ex: cube_root(-1) = -1. This is easily achieved with this function.
def solve_general_cubic(a: float, b: float, sub: float) ‑> Tuple[complex, complex, complex]-
Solves general cubic polynomial
Given a and b, the coefficients of a depressed cubic polynomial on the form t^3 + at + b, and the substitution used to obtain the depressed form, it will find the three roots of the polynomial.
By using either Cardano's formula or the trigonometric cubic equation, we garatuee three solutions. With cubics stemming from bezier curves we can further guaratee a real solution on [0, 1]^2.
Args
a- coefficient of the linear term
b- constant term
sub- the lambda value used for substitution when calculating the depressed form, t = u - lambda
Returns
A tuple of three roots of the equation, one is guaranteed to be real, the others are either complex or real.