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

简介: 【OpenCV】仿射变换中cv2.estimateAffine2D 的原理

一、介绍

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

       先来看代码:

import cv2
import numpy as np
 
# 原始点集
srcPoints = np.array([[50, 50], [200, 50], [50, 200]], dtype=np.float32)
# 目标点集
dstPoints = np.array([[70, 100], [220, 70], [150, 250]], dtype=np.float32)
 
# 估计仿射变换矩阵
M, inliers = cv2.estimateAffine2D(srcPoints, dstPoints)
 
# 打印估计得到的仿射变换矩阵
print('M:\n', M)
'''
M:
[[ 1.          0.53333333 -6.66666667]
 [-0.2         1.         60.        ]]
'''
 
print('inliers:\n', inliers)
'''
inliers:
 [[1]
 [1]
 [1]]
'''

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

二、仿射变换矩阵 (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.计算旋转角度

       旋转角度的计算公式:

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

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

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

3.M的计算过程

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

      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:

eq.png

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


       需要注意的是,由于存在噪声和异常值的影响,估计的仿射变换矩阵可能不是完全准确的。因此,输出的仿射变换矩阵 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 坐标按照如下方式进行变换:

       


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

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

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

(2)垂直错切

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

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


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

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

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


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

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

相关文章
|
3月前
|
计算机视觉 C++
基于VS2019和Opencv4,对hsv颜色空间的图像分割原理以及实现
这篇文章介绍了基于HSV颜色空间的图像分割原理,包括HSV模型的基本概念和如何在OpenCV中通过设置HSV的色彩范围来实现图像中特定颜色的物体分割,并通过示例代码展示了在静态图像和视频流中进行颜色分割的方法。
基于VS2019和Opencv4,对hsv颜色空间的图像分割原理以及实现
|
5月前
|
计算机视觉
opencv之形态变换
opencv之形态变换
|
5月前
|
算法 计算机视觉
【Qt&OpenCV 图像的形态学变换 morpholgyEx】
【Qt&OpenCV 图像的形态学变换 morpholgyEx】
36 0
|
6月前
|
存储 编解码 算法
【OpenCV】-霍夫变换
【OpenCV】-霍夫变换
|
6月前
|
计算机视觉 Python
轻松掌握opencv的8种图像变换
轻松掌握opencv的8种图像变换
|
6月前
|
计算机视觉
【OpenCV】-仿射变换
【OpenCV】-仿射变换
|
6月前
|
计算机视觉
OpenCV几何变换
OpenCV几何变换
39 0
|
6月前
|
计算机视觉
OpenCV(二十七):图像距离变换
OpenCV(二十七):图像距离变换
62 0
|
11月前
|
JavaScript 算法 计算机视觉
一款简单图像变换工具基于 opencv ,docker ,jquery
一款简单图像变换工具基于 opencv ,docker ,jquery
56 1
|
6月前
|
算法 数据挖掘 计算机视觉
OpenCV中应用尺度不变特征变换SIFT算法讲解及实战(附源码)
OpenCV中应用尺度不变特征变换SIFT算法讲解及实战(附源码)
78 0