给出三点计算仿射变换

时间:2014-04-09 06:13:22

标签: matlab image-processing geometry computer-vision linear-algebra

我有两个图像,使用筛选找到三个相似的2D点。我需要计算图像之间的仿射变换。不幸的是,我错过了讲座,那里的信息对我来说有点密集。计算这个2x3矩阵的一般方法是什么?

我有一个2x3矩阵中的点矩阵[x1 y1; x2 y2; x3 y3]但我从那里迷失了。 谢谢你的帮助。

4 个答案:

答案 0 :(得分:33)

通常,2D点的仿射变换被表示为

x' = A*x

x是原始2D位置的三向量[x; y; 1]x'是转换点。仿射矩阵A

A = [a11 a12 a13;
     a21 a22 a23;
       0   0   1]

xA 知道且您希望恢复x'时,此表单非常有用。

但是,您可以用不同的方式表达这种关系。 让

X = [xi yi 1  0  0  0;
      0  0 0 xi yi  1 ]

a是列向量

a = [a11; a12; a13; a21; a22; a23]

然后

X*a = [xi'; yi']

保留所有对应点x_i, x_i'对。

当您知道点对之间的对应关系并希望恢复A的参数时,此替代形式非常有用。
将所有点堆叠在一个大矩阵X(每个点两行)中,您将得到2 * n×6矩阵X乘以未知数的6向量{{1} }等于堆叠对应点的2 * n×1列向量(由a表示):

x_prime

解决X*a = x_prime

a

以最小二乘意义恢复a = X \ x_prime 的参数。

祝你好运并停止上课!

答案 1 :(得分:1)

很抱歉,您没有使用Matlab,但我只使用了Python。我认为这段代码可能会对您有所帮助(对不起,不好的代码风格-我是数学家,而不是程序员)

import numpy as np
# input data
ins = [[1, 1], [2, 3], [3, 2]]  # <- points
out = [[0, 2], [1, 2], [-2, -1]] # <- mapped to
# calculations
l = len(ins)
B = np.vstack([np.transpose(ins), np.ones(l)])
D = 1.0 / np.linalg.det(B)
entry = lambda r,d: np.linalg.det(np.delete(np.vstack([r, B]), (d+1), axis=0))
M = [[(-1)**i * D * entry(R, i) for i in range(l)] for R in np.transpose(out)]
A, t = np.hsplit(np.array(M), [l-1])
t = np.transpose(t)[0]
# output
print("Affine transformation matrix:\n", A)
print("Affine transformation translation vector:\n", t)
# unittests
print("TESTING:")
for p, P in zip(np.array(ins), np.array(out)):
  image_p = np.dot(A, p) + t
  result = "[OK]" if np.allclose(image_p, P) else "[ERROR]"
  print(p, " mapped to: ", image_p, " ; expected: ", P, result)

此代码演示了如何将仿射变换恢复为矩阵和向量,并测试了初始点已映射到它们应在的位置。您可以使用Google colab测试此代码,因此无需安装任何程序。可能您可以将其翻译为Matlab。

关于此代码背后的理论:它基于“ Beginner's guide to mapping simplexes affinely”中给出的方程式,矩阵恢复在“规范符号的恢复”部分中进行了描述。同一作者发表了“ Workbook on mapping simplexes affinely”,其中包含许多此类实际示例。

答案 2 :(得分:1)

为了在 OpenCV 中实现,您可以使用 cv2.getAffineTransform

getAffineTransform() [1/2]

Mat cv::getAffineTransform  (   const Point2f   src[],
    const Point2f   dst[] 
)   

Python:

cv.getAffineTransform(  src, dst    ) ->    retval

答案 3 :(得分:0)

这适用于任何想用 C 语言进行的人。算法基于此 MathStackExchange post。作者展示了如何使用 Gauss-Jordan 消元法求仿射变换系数的公式,

/*
*Function: Affine Solver
*Role: Finds Affine Transforming mapping (X,Y) to (X',Y')
*Input: double array[A,B,C,D,E,F], 
*   int array[X-Coordinates], int array[Y-Coordinates],
*   int array[X'-Coordinates],int array[Y'-Coordinates]
*Output:void - Fills double array[A,B,C,D,E,F]
*/

void AffineSolver(double *AtoF, int *X, int *Y, int *XP, int *YP)
{
    AtoF[0] = (double)(XP[1]*Y[0] - XP[2]*Y[0] - XP[0]*Y[1] + XP[2]*Y[1] + XP[0]*Y[2] -XP[1]*Y[2]) / 
          (double)(X[1]*Y[0] - X[2]*Y[0] - X[0]*Y[1] + X[2]*Y[1] + X[0]*Y[2] - X[1]*Y[2]);
          
    AtoF[1] = (double)(XP[1]*X[0] - XP[2]*X[0] - XP[0]*X[1] + XP[2]*X[1] + XP[0]*X[2] -XP[1]*X[2]) / 
          (double)(-X[1]*Y[0] + X[2]*Y[0] + X[0]*Y[1] - X[2]*Y[1] - X[0]*Y[2] +X[1]*Y[2]);
          
    AtoF[2] = (double)(YP[1]*Y[0] - YP[2]*Y[0] - YP[0]*Y[1] + YP[2]*Y[1] + YP[0]*Y[2] -YP[1]*Y[2]) / 
          (double)(X[1]*Y[0] - X[2]*Y[0] - X[0]*Y[1] + X[2]*Y[1] + X[0]*Y[2] - X[1]*Y[2]);
          
    AtoF[3] = (double)(YP[1]*X[0] - YP[2]*X[0] - YP[0]*X[1] + YP[2]*X[1] + YP[0]*X[2] -YP[1]*X[2]) / 
          (double)(-X[1]*Y[0] + X[2]*Y[0] + X[0]*Y[1] - X[2]*Y[1] - X[0]*Y[2] +X[1]*Y[2]);
          
    AtoF[4] = (double)(XP[2]*X[1]*Y[0] - XP[1]*X[2]*Y[0]-XP[2]*X[0]*Y[1] + XP[0]*X[2]*Y[1]+
           XP[1]*X[0]*Y[2] - XP[0]*X[1]*Y[2]) / 
          (double)(X[1]*Y[0] - X[2]*Y[0] - X[0]*Y[1] + X[2]*Y[1] + X[0]*Y[2] - X[1]*Y[2]);
          
    AtoF[5] = (double)(YP[2]*X[1]*Y[0] - YP[1]*X[2]*Y[0]-YP[2]*X[0]*Y[1] + YP[0]*X[2]*Y[1] + YP[1]*X[0]*Y[2] -            YP[0]*X[1]*Y[2]) / 
          (double)(X[1]*Y[0] - X[2]*Y[0] - X[0]*Y[1] + X[2]*Y[1] + X[0]*Y[2] - X[1]*Y[2]);
}

/*
*Function: PrintMatrix
*Role: Prints 2*3 matrix as //a b e
                //c d f
*Input: double array[ABCDEF]
*Output: voids
*/

void PrintMatrix(double *AtoF)
{
    printf("a = %f ",AtoF[0]);
    printf("b = %f ",AtoF[1]);
    printf("e = %f\n",AtoF[4]);
    printf("c = %f ",AtoF[2]);
    printf("d = %f ",AtoF[3]);
    printf("f = %f ",AtoF[5]);
}

int main()
{
/*Test*/
/*Find transform mapping (0,10),(0,0),(10,0) to (0,5)(0,0)(5,0)*/
/*Expected Output*/
//a = 0.500000 b = 0.000000 e = -0.000000
//c = -0.000000 d = 0.500000 f = -0.000000
/*Test*/
    double *AtoF = calloc(6, sizeof(double));
    int  X[] = { 0, 0,10};
    int  Y[] = {10, 0, 0};
    int XP[] = { 0, 0, 5};
    int YP[] = { 5, 0, 0};
    AffineSolver(AtoF,X,Y,XP,YP);
    PrintMatrix(AtoF);
    free(AtoF);
    return 0;
}