• 【OpenCV】仿射变换中cv2.estimateAffine2D 的原理


    目录

    一、介绍

    二、仿射变换矩阵 (M)

    1.M中六个元素的说明

    2.计算旋转角度

    3.M的计算过程

    三、输出状态 (inliers)

    四、错切参数

    1.错切参数的定义

    2.错切参数例子

    (1)水平错切

    (2)垂直错切


    一、介绍

            cv2.estimateAffine2D 是 OpenCV 库中的一个函数,用于估计两个二维点集之间的仿射变换矩阵。即第一个点集经仿射变换转换到第二个点集需要的操作,包括缩放、旋转和平移。

            先来看代码:

    1. import cv2
    2. import numpy as np
    3. # 原始点集
    4. srcPoints = np.array([[50, 50], [200, 50], [50, 200]], dtype=np.float32)
    5. # 目标点集
    6. dstPoints = np.array([[70, 100], [220, 70], [150, 250]], dtype=np.float32)
    7. # 估计仿射变换矩阵
    8. M, inliers = cv2.estimateAffine2D(srcPoints, dstPoints)
    9. # 打印估计得到的仿射变换矩阵
    10. print('M:\n', M)
    11. '''
    12. M:
    13. [[ 1. 0.53333333 -6.66666667]
    14. [-0.2 1. 60. ]]
    15. '''
    16. print('inliers:\n', inliers)
    17. '''
    18. inliers:
    19. [[1]
    20. [1]
    21. [1]]
    22. '''

            从上面的代码中可以看到,函数的输入是两个参数,分别表示原始点集和目标点集。函数的输出参数包括两个部分:仿射变换矩阵和输出状态。

    二、仿射变换矩阵 (M)

            第一个返回值是一个 2x3 的浮点型矩阵,表示从原始点集到目标点集的仿射变换。矩阵的前两列是旋转和缩放的部分,最后一列是平移的部分。可以使用这个矩阵来将原始图像或点集进行仿射变换,使其与目标图像或点集对齐。

    1.M中六个元素的说明

            M[0,0]:表示x方向上的缩放。大于 1,则表示进行了放大操作;小于 1,则表示进行了缩小操作;等于 1,则表示没有进行缩放操作。

            M[0,1]:表示垂直错切参数,与M[1,0]一起用于计算旋转角度。

            M[0,2]:表示x方向上的平移。

            M[1,0]:表示水平错切参数,与M[1,1]一起用于计算旋转角度。

            M[1,1]:表示y方向上的缩放。大于 1,则表示进行了放大操作;小于 1,则表示进行了缩小操作;等于 1,则表示没有进行缩放操作。

            M[1,2]:表示y方向上的平移。

    2.计算旋转角度

            旋转角度的计算公式:

    angle = atan2(M[1, 0], M[0, 0])

            其中,atan2 是一个反三角函数,用于计算给定的 y 值和 x 值的反正切值。这个角度表示原始点集经过变换后的旋转角度。

    代码如下,np.arctan2返回的是弧度值,如果需要角度值还需要再转换一下:

    1. # 得到弧度值
    2. da = np.arctan2(m[1, 0], m[0, 0])
    3. # 得到角度值
    4. theta_deg = np.degrees(da)

    3.M的计算过程

            1. 首先,根据输入的原始点集 srcPoints 和目标点集 dstPoints,构建一个线性方程系统。对于每个点对 (srcPoint, dstPoint),构建以下两个方程:

    \left\{\begin{matrix} dstPoint.x = M[0, 0] * srcPoint.x + M[0, 1] * srcPoint.y + M[0, 2] \\ dstPoint.y = M[1, 0] * srcPoint.x + M[1, 1] * srcPoint.y + M[1, 2] \end{matrix}\right.

            2. 将线性方程系统转化为矩阵形式 A * X = B,其中:

            A 是一个 2N x 6 的矩阵,其中 N 是点对的数量。A 的每一行对应一个点对,包含原始点的坐标和一个常数项。

            X 是一个 6 x 1 的矩阵,表示待求解的仿射变换矩阵的参数。

            B 是一个 2N x 1 的矩阵,包含目标点的坐标。

            3. 使用最小二乘法来求解矩阵 X,使得 A * X 尽可能接近 B。最小二乘法的目标是最小化残差的平方和。

            4. 根据求解得到的矩阵 X,构建估计的仿射变换矩阵 M:

    \begin{matrix} \\ M[0, 0] = X[0] \\ M[0, 1] = X[1] \\ M[0, 2] = X[2] \\ M[1, 0] = X[3] \\ M[1, 1] = X[4] \\ M[1, 2] = X[5] \end{matrix}

            最小二乘法的目标是找到一个最优的仿射变换矩阵,使得原始点集经过变换后与目标点集尽可能接近。通过最小化残差的平方和,可以得到一个最优的估计结果。

            需要注意的是,由于存在噪声和异常值的影响,估计的仿射变换矩阵可能不是完全准确的。因此,输出的仿射变换矩阵 M 可能只是一个近似的估计结果,需要根据实际情况进行评估和调整。

    三、输出状态 (inliers)

            inliers是一个整数或浮点数的向量,表示每个输入点对应的输出点是否被认为是内点(inlier)。内点是指在估计仿射变换时被认为是一致的点。输出状态的长度与输入点集的数量相同,每个元素的值为 0 或 1,其中 1 表示对应的点是内点,0 表示对应的点是外点(outlier)。

            cv2.estimateAffine2D确定内点(inliers)的算法有三个可选:

            cv2.RANSAC: 使用 RANSAC 算法进行估计。该选项适用于存在较多离群点的情况,可以提高估计的鲁棒性,这也是默认参数。
            cv2.LMEDS: 使用最小中值估计(Least-Median Estimation,LMedS)算法进行估计。该选项适用于存在少量离群点的情况,可以提高估计的准确性。
            cv2.RHO: 使用 RHO 算法进行估计。该选项适用于存在较多离群点的情况,可以提高估计的鲁棒性。

            可以通过下面的方式修改内点检测方式:

    M, inliers = cv2.estimateAffine2D(srcPoints, dstPoints, cv2.RHO)

    四、错切参数

    1.错切参数的定义

            上面提到了一个名词叫错切参数,这里解释一下。错切参数(Shear parameters)是一种用于描述错切变换的数值参数。在二维图形变换中,错切变换是一种线性变换,它通过改变图形的形状来实现。

            在二维平面上,错切变换是一种将对象沿着水平或垂直方向进行平移和拉伸的变换。它会改变对象的形状,使其在一个方向上相对于另一个方向发生倾斜。

            在错切变换中,有两个主要的错切参数:水平错切参数(shear parameter)和垂直错切参数(shear parameter)。这些参数决定了在水平和垂直方向上的错切程度。
            水平错切参数(shx):它表示在水平方向上的错切程度。当 shx 的值为正时,图形在水平方向上向右上方倾斜;当 shx 的值为负时,图形在水平方向上向左上方倾斜;当 shx 的值为零时,表示没有水平方向上的错切变换。

            垂直错切参数(shy):它表示在垂直方向上的错切程度。当 shy 的值为正时,图形在垂直方向上向右下方倾斜;当 shy 的值为负时,图形在垂直方向上向左下方倾斜;当 shy 的值为零时,表示没有垂直方向上的错切变换。

            这些错切参数可以通过仿射变换矩阵中的相应元素来表示。在二维仿射变换矩阵中,水平错切参数通常对应于矩阵的第一行第二列元素(M[0, 1]),而垂直错切参数通常对应于矩阵的第二行第一列元素(M[1, 0])。

    2.错切参数例子

            以下是一个示例,说明如何使用错切参数对对象进行变形:

    (1)水平错切

            水平错切就是原图每个像素的y不变,x根据M[0,1]进行线性变换。

            假设有一个矩形对象,原始的顶点坐标为 (x1, y1), (x2, y2), (x3, y3), (x4, y4)。要对该矩形进行水平方向的错切变形,可以使用错切参数 shx,并将每个顶点的 x 坐标按照如下方式进行变换:

            \begin{matrix} \\ x_1{new} = x_{1} + shx * y_1 \\ x_2{new} = x_{2} + shx * y_2 \\ x_3{new} = x_3 + shx * y_3 \\ x_4{new} = x_4 + shx * y_4 \end{matrix}

            这样,通过调整 shx 的值,可以控制矩形在水平方向上的错切程度。

            下面是水平错切的代码和结果:

    1. import cv2
    2. import numpy as np
    3. img_path = r'test.jpg'
    4. target_path = r'test_1.jpg'
    5. scale = 0.3 # 变换的比例
    6. img = cv2.imread(img_path)
    7. # 构造错切变换矩阵
    8. M = np.float32([[1, scale, 0], [0, 1, 0]])
    9. h, w, _ = img.shape
    10. img_shear = cv2.warpAffine(img, M, (w + int(scale * h), h))
    11. cv2.imwrite(target_path, img_shear)

    (2)垂直错切

            垂直错切就是原图每个像素的x不变,y根据M[1,0]进行线性变换。

            要对矩形进行垂直方向的错切变形,可以使用错切参数 shy,并将每个顶点的 y 坐标按照如下方式进行变换:

    \begin{matrix} \\ x_1{new} = shx * x_{1} + y_1 \\ x_2{new} = shx * x_{2} + y_2 \\ x_3{new} = shx * x_3 + y_3 \\ x_4{new} = shx * x_4 + y_4 \end{matrix}

            通过调整 shy 的值,可以控制矩形在垂直方向上的错切程度。

            下面是垂直错切的代码和结果:

    1. import cv2
    2. import numpy as np
    3. img_path = r'test.jpg'
    4. target_path = r'test_2.jpg'
    5. scale = 0.3 # 变换的比例
    6. img = cv2.imread(img_path)
    7. # 构造错切变换矩阵
    8. M = np.float32([[1, 0, 0], [scale, 1, 0]])
    9. h, w, _ = img.shape
    10. img_shear = cv2.warpAffine(img, M, (w, h + int(scale * w)))
    11. cv2.imwrite(target_path, img_shear)



            需要注意的是,错切参数的值可以是正数、负数或零,具体取决于所需的错切方向和程度。

            cv2.estimateAffine2D 的原理就介绍到这里,关注不迷路(#^.^#)

  • 相关阅读:
    云计算-Linux-小综合实验答案
    hive 常用函数
    域内创建机器用户
    从飞天到倚天 阿里云底层自研技术大爆发
    WPF中动画
    Word格式处理控件Aspose.Words for .NET教程——使用超链接和HTML
    【前端】JavaScript
    idea快捷键
    2093409-57-3,DBCO-PEG3-amine,DBCO-PEG3-NH2,二苯并环辛炔-三聚乙二醇-氨基供应
    Zookeeper
  • 原文地址:https://blog.csdn.net/xian0710830114/article/details/134462764