OpenCV 提供:
getRotationMatrix2D
获取由 center
、angle
和 scale
getAffineTransform
获得由三对点定义的 2x3 变换矩阵(旋转、缩放、平移、剪切)。我想从两对点获得一个具有旋转、缩放和平移(即无剪切)的变换矩阵。
这是我当前的实现,它有效,但对我来说太复杂了:
from typing import Tuple, List
import cv2
import numpy as np
import numpy.typing
def _third_triangle_point(p1: Tuple[float, float], p2: Tuple[float, float]) -> Tuple[float, float]:
"""Calculate the third point of an isosceles right-angled triangle."""
p1_arr = np.array(p1, dtype=np.float32)
p2_arr = np.array(p2, dtype=np.float32)
diff = p2_arr - p1_arr
perpendicular = np.array((diff[1], -diff[0]), dtype=np.float32)
result = p1_arr + perpendicular
return result[0], result[1]
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]:
# cv2.getAffineTransform takes three point pairs.
# It supports rotation, translation, scaling, and shearing.
# We don't need the shearing,
# so we invent a third point with a stable relation to the given two.
return cv2.getAffineTransform( # type: ignore
_stack_points([src[0], src[1], _third_triangle_point(src[0], src[1])]),
_stack_points([dst[0], dst[1], _third_triangle_point(dst[0], dst[1])])
)
print(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]]
有没有更简单的方法可以达到相同的结果?
解决办法很简单,只需使用
estimateAffinePartial2D
:
from typing import Tuple
import cv2
import numpy as np
import numpy.typing
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]:
return cv2.estimateAffinePartial2D(np.array([src[0], src[1]]), np.array([dst[0], dst[1]]))[0] # type: ignore
print(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]]