Quantcast
Viewing all articles
Browse latest Browse all 14069

How to obtain a 2d transformation matrix from two pairs of points?

OpenCV provides:

  • getRotationMatrix2D to get a 2x3 transformation matrix (rotation, scale, shift) defined by center, angle and scale
  • getAffineTransform to get a 2x3 transformation matrix (rotation, scale, shift, sheer) defined by three pairs of points.

I'd like to get a transformation matrix with rotation, scale, and shift (i.e. no sheer) from two pairs of points.

Here is my current implementation, which works, but it's way too complex for my taste:

from typing import Tuple, Listimport cv2import numpy as npimport numpy.typingdef invert_vector(v: Tuple[float, float]) -> Tuple[float, float]:    return -v[0], -v[1]def add_vectors(v1: Tuple[float, float], v2: Tuple[float, float]) -> Tuple[float, float]:    return v2[0] + v1[0], v2[1] + v1[1]def subtract_vectors(v1: Tuple[float, float], v2: Tuple[float, float]) -> Tuple[float, float]:    return add_vectors(v1, invert_vector(v2))def cross2d(point: Tuple[float, float]) -> Tuple[float, float]:    return point[1], -point[0]def get_third_point(p1: Tuple[float, float], p2: Tuple[float, float]) -> Tuple[float, float]:    diff = subtract_vectors(p1, p2)    return add_vectors(p1, cross2d(diff))def stack_points(points: List[Tuple[float, float]]) -> np.typing.NDArray[np.float32]:    return np.vstack([np.array(p, dtype=np.float32) for p in points])def get_transformation_between_two_point_pairs(        src: Tuple[Tuple[float, float], Tuple[float, float]],        dst: Tuple[Tuple[float, float], Tuple[float, float]]) -> np.typing.NDArray[np.float32]:    # We don't actually need a full affine transformation (rotation/translation/scaling/sheering).    # A rotation/translation/scaling matrix does suffice.    # But cv2.getRotationMatrix2D does not take two point pairs, but instead center, angle, and scale.    # To avoid needing to derive these from our two point pairs,    # we instead invent a third point to have stable a triangle (isosceles, right-angled).    # pylint: disable=no-member    return cv2.getAffineTransform(  # type: ignore        stack_points([src[0], src[1], get_third_point(src[0], src[1])]),        stack_points([dst[0], dst[1], get_third_point(dst[0], dst[1])])    )    # pylint: enable=no-memberprint(get_transformation_between_two_point_pairs(((10, 10), (17, 23)), ((30, 30), (70, 30))))
[[ 1.28440367  2.3853211  -6.69724771] [-2.3853211   1.28440367 41.00917431]]

Is there a simpler way to achieve the same result?


Viewing all articles
Browse latest Browse all 14069

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>