Reference
Personal understanding of the perspective transformation principle and the python implementation of the transformation matrix
may be wrong, welcome to discuss.
To perform perspective transformation, four points need to be selected. These points define a rectangle, but in the original image, due to problems such as camera angles, it does not appear to be a rectangle. In order to change the perspective, we need to perform perspective transformation.
Perspective transformation essentially converts a picture from one perspective to another through a linear transformation between four points.
Calculation formula
Perspective transformation matrix:
We define the target point matrix as , and define the source point matrix as .
This is mapping from two-dimensional pixel coordinates to three-dimensional world coordinates. Our main goal here is to map pixel coordinates to another pixel coordinates.
For
each pair, the following equations are satisfied.
Therefore, we can get the formula (1) and multiply it
up and down, and continue to deduce it:
we need to find , and the other is the unknown, and convert the equation into a matrix AX = 0 AX=0AX=0
There are 9 unknowns at this time, we need to use 9 equations to solve, for a pair of matching pointswe can get two equations.
Why do we only need 4 pairs of matching points to solve the above equation.
8 unknowns
We found that for formula (1) can be written in the following form, the result will not change.
where α \alphaα is a number that is not 0.
At this point, we can map the above formula back to the matrix form, and we can get.
Therefore, we can get
that there are only 8 unknowns at this point, and we only need to find 4 sets of corresponding points to solve the equation.
The reaction to the solution formula is as follows.
The last digit is a constant 1, we can modify the formula as formula
Code solution - realize it yourself
# 此处的src是原坐标数组,dst是目标坐标数组
def WarpPerspectiveMatrix(src, dst):
assert src.shape[0] == dst.shape[0] and src.shape[0] >= 4
nums = src.shape[0]
# 4组对应点,每组2行8列
# 总共8行8列的数组,对应公式(3)中最左边的矩阵
A = np.zeros((2 * nums, 8))
# 4组对应点,每组2行1列
# 总共8行1列,对应公式(3)中最右边的矩阵
B = np.zeros((2 * nums, 1))
# 矩阵赋值,0下标为x值,1下标为y值
for i in range(0, nums):
A_i = src[i,:]
B_i = dst[i,:]
A[2*i, :] = [A_i[0], A_i[1], 1, 0, 0, 0, -A_i[0]*B_i[0], -A_i[1]*B_i[0]]
B[2*i] = B_i[0]
A[2*i+1, :] = [0, 0 , 0, A_i[0], A_i[1], 1, -A_i[0]*B_i[1], -A_i[1]*B_i[1]]
B[2*i+1] = B_i[1]
# 转换为矩阵
A = np.mat(A)
# 求解未知数值,.I表示求逆
warpMatrix = A.I * B
# 矩阵后处理,主要是将a33的1值赋值回去
warpMatrix = np.array(warpMatrix).T[0]
warpMatrix = np.insert(warpMatrix, warpMatrix.shape[0], values=1.0, axis=0)
warpMatrix = warpMatrix.reshape((3, 3))
return warpMatrix
Code solution - Opencv implementation
# 注意,这里的src和dst,本人验证,使用np.float32()定义可以不出错
M = cv2.getPerspectiveTransform(src, dst)
src = np.float32([[34 * 720 / 160, 113 * 1280 / 288], [34 * 720 / 160, 186 * 1280 / 288], [157 * 720 / 160, 50 * 1280 / 288], [157 * 720 / 160, 244 * 1280 / 288]])
dst = np.float32([[150, 50], [150, 490], [780, 50], [780, 490]])
def WarpPerspectiveMatrix(src, dst):
assert src.shape[0] == dst.shape[0] and src.shape[0] >= 4
nums = src.shape[0]
A = np.zeros((2 * nums, 8))
B = np.zeros((2 * nums, 1))
for i in range(0, nums):
A_i = src[i,:]
B_i = dst[i,:]
A[2*i, :] = [A_i[0], A_i[1], 1, 0, 0, 0, -A_i[0]*B_i[0], -A_i[1]*B_i[0]]
B[2*i] = B_i[0]
A[2*i+1, :] = [0, 0 , 0, A_i[0], A_i[1], 1, -A_i[0]*B_i[1], -A_i[1]*B_i[1]]
B[2*i+1] = B_i[1]
A = np.mat(A)
warpMatrix = A.I * B
warpMatrix = np.array(warpMatrix).T[0]
warpMatrix = np.insert(warpMatrix, warpMatrix.shape[0], values=1.0, axis=0)
warpMatrix = warpMatrix.reshape((3, 3))
return warpMatrix
M = WarpPerspectiveMatrix(src, dst)
print(M)
M = cv2.getPerspectiveTransform(src, dst)
print(M)
# 自己实现的
[[ 6.41178433e+00 0.00000000e+00 -7.04158205e+02]
[ 1.54253726e+00 2.50298025e+00 -1.40077892e+03]
[ 5.52700641e-03 0.00000000e+00 1.00000000e+00]]
# opencv官方的
[[ 6.41178433e+00 0.00000000e+00 -7.04158205e+02]
[ 1.54253726e+00 2.50298025e+00 -1.40077892e+03]
[ 5.52700641e-03 -1.08420217e-19 1.00000000e+00]]