Я решил это, используя ответ morotspaj из сообщения ниже и Matlab.
Рассчитайте однородную матрицу преобразования перспективы 2D из 4 балла в MATLAB
ui и vi уже известны (они равны разрешению картинки), поэтому я заполнил их в матрицу 8x8 и получил следующее:
/ x0 y0 1 0 0 0 0 0 \ /m00\ / 0 \
| x1 y1 1 0 0 0 -x1*RES_H -y1*RES_H | |m01| |RES_H|
| x2 y2 1 0 0 0 0 0 | |m02| | 0 |
| x3 y3 1 0 0 0 -x3*RES_H -y3*RES_H |.|m10|=|RES_H|
| 0 0 0 x0 y0 1 0 0 | |m11| | 0 |
| 0 0 0 x1 y1 1 0 0 | |m12| | 0 |
| 0 0 0 x2 y2 1 -x2*RES_V -y2*RES_V | |m20| |RES_V|
\ 0 0 0 x3 y3 1 -x3*RES_V -y3*RES_V / \m21/ \RES_V/
Где RES_H = (640 - 1) и RES_V = (480 - 1). Это уравнение можно представить как Ax = b. Я поместил матрицу A (8x8) и вектор b (8x1) в Matlab и использовал linsolve (A, b strong>) для решения линейной системы:
syms x0 x1 x2 x3 y0 y1 y2 y3 RES_H RES_V;
A = [ x0 y0 1 0 0 0 0 0 ; x1 y1 1 0 0 0 -x1*RES_H -y1*RES_H ; x2 y2 1 0 0 0 0 0 ; x3 y3 1 0 0 0 -x3*RES_H -y3*RES_H ; 0 0 0 x0 y0 1 0 0 ; 0 0 0 x1 y1 1 0 0 ; 0 0 0 x2 y2 1 -x2*RES_V -y2*RES_V ; 0 0 0 x3 y3 1 -x3*RES_V -y3*RES_V ];
b = [ 0 ; RES_H ; 0 ; RES_H ; 0 ; 0 ; RES_V ; RES_V ];
simplify(linsolve(A,B))
Результат был следующий:
m00 = -(RES_H*(y0 - y2)*(x0*y1 - x1*y0 - x0*y3 + x3*y0 + x1*y3 - x3*y1)*(x1*y2 - x2*y1 - x1*y3 + x3*y1 + x2*y3 - x3*y2))/(- x0*x0*x1*y1*y2*y2 + 2*x0*x0*x1*y1*y2*y3 - x0*x0*x1*y1*y3*y3 + x0*x0*x2*y1*y1*y2 - 2*x0*x0*x2*y1*y2*y3 + x0*x0*x2*y2*y3*y3 - 2*x0*x0*x3*y1*y1*y2 + x0*x0*x3*y1*y1*y3 + 2*x0*x0*x3*y1*y2*y2 - x0*x0*x3*y2*y2*y3 + x0*x1*x1*y0*y2*y2 - 2*x0*x1*x1*y0*y2*y3 + x0*x1*x1*y0*y3*y3 - 2*x0*x1*x2*y0*y1*y3 + 2*x0*x1*x2*y0*y2*y3 + 2*x0*x1*x2*y1*y3*y3 - 2*x0*x1*x2*y2*y3*y3 + 2*x0*x1*x3*y0*y1*y2 - 2*x0*x1*x3*y0*y2*y2 - 2*x0*x1*x3*y1*y2*y3 + 2*x0*x1*x3*y2*y2*y3 - x0*x2*x2*y0*y1*y1 + 2*x0*x2*x2*y0*y1*y3 - x0*x2*x2*y0*y3*y3 + 2*x0*x2*x3*y0*y1*y1 - 2*x0*x2*x3*y0*y1*y2 - 2*x0*x2*x3*y1*y1*y3 + 2*x0*x2*x3*y1*y2*y3 - x0*x3*x3*y0*y1*y1 + x0*x3*x3*y0*y2*y2 + 2*x0*x3*x3*y1*y1*y2 - 2*x0*x3*x3*y1*y2*y2 - x1*x1*x2*y0*y0*y2 + 2*x1*x1*x2*y0*y0*y3 - 2*x1*x1*x2*y0*y3*y3 + x1*x1*x2*y2*y3*y3 - x1*x1*x3*y0*y0*y3 + 2*x1*x1*x3*y0*y2*y3 - x1*x1*x3*y2*y2*y3 + x1*x2*x2*y0*y0*y1 - 2*x1*x2*x2*y0*y0*y3 + 2*x1*x2*x2*y0*y3*y3 - x1*x2*x2*y1*y3*y3 - 2*x1*x2*x3*y0*y0*y1 + 2*x1*x2*x3*y0*y0*y2 + 2*x1*x2*x3*y0*y1*y3 - 2*x1*x2*x3*y0*y2*y3 + x1*x3*x3*y0*y0*y1 - 2*x1*x3*x3*y0*y1*y2 + x1*x3*x3*y1*y2*y2 + x2*x2*x3*y0*y0*y3 - 2*x2*x2*x3*y0*y1*y3 + x2*x2*x3*y1*y1*y3 - x2*x3*x3*y0*y0*y2 + 2*x2*x3*x3*y0*y1*y2 - x2*x3*x3*y1*y1*y2);
m01 = (RES_H*(x0 - x2)*(x0*y1 - x1*y0 - x0*y3 + x3*y0 + x1*y3 - x3*y1)*(x1*y2 - x2*y1 - x1*y3 + x3*y1 + x2*y3 - x3*y2))/(- x0*x0*x1*y1*y2*y2 + 2*x0*x0*x1*y1*y2*y3 - x0*x0*x1*y1*y3*y3 + x0*x0*x2*y1*y1*y2 - 2*x0*x0*x2*y1*y2*y3 + x0*x0*x2*y2*y3*y3 - 2*x0*x0*x3*y1*y1*y2 + x0*x0*x3*y1*y1*y3 + 2*x0*x0*x3*y1*y2*y2 - x0*x0*x3*y2*y2*y3 + x0*x1*x1*y0*y2*y2 - 2*x0*x1*x1*y0*y2*y3 + x0*x1*x1*y0*y3*y3 - 2*x0*x1*x2*y0*y1*y3 + 2*x0*x1*x2*y0*y2*y3 + 2*x0*x1*x2*y1*y3*y3 - 2*x0*x1*x2*y2*y3*y3 + 2*x0*x1*x3*y0*y1*y2 - 2*x0*x1*x3*y0*y2*y2 - 2*x0*x1*x3*y1*y2*y3 + 2*x0*x1*x3*y2*y2*y3 - x0*x2*x2*y0*y1*y1 + 2*x0*x2*x2*y0*y1*y3 - x0*x2*x2*y0*y3*y3 + 2*x0*x2*x3*y0*y1*y1 - 2*x0*x2*x3*y0*y1*y2 - 2*x0*x2*x3*y1*y1*y3 + 2*x0*x2*x3*y1*y2*y3 - x0*x3*x3*y0*y1*y1 + x0*x3*x3*y0*y2*y2 + 2*x0*x3*x3*y1*y1*y2 - 2*x0*x3*x3*y1*y2*y2 - x1*x1*x2*y0*y0*y2 + 2*x1*x1*x2*y0*y0*y3 - 2*x1*x1*x2*y0*y3*y3 + x1*x1*x2*y2*y3*y3 - x1*x1*x3*y0*y0*y3 + 2*x1*x1*x3*y0*y2*y3 - x1*x1*x3*y2*y2*y3 + x1*x2*x2*y0*y0*y1 - 2*x1*x2*x2*y0*y0*y3 + 2*x1*x2*x2*y0*y3*y3 - x1*x2*x2*y1*y3*y3 - 2*x1*x2*x3*y0*y0*y1 + 2*x1*x2*x3*y0*y0*y2 + 2*x1*x2*x3*y0*y1*y3 - 2*x1*x2*x3*y0*y2*y3 + x1*x3*x3*y0*y0*y1 - 2*x1*x3*x3*y0*y1*y2 + x1*x3*x3*y1*y2*y2 + x2*x2*x3*y0*y0*y3 - 2*x2*x2*x3*y0*y1*y3 + x2*x2*x3*y1*y1*y3 - x2*x3*x3*y0*y0*y2 + 2*x2*x3*x3*y0*y1*y2 - x2*x3*x3*y1*y1*y2);
m02 = -(RES_H*(x0*y2 - x2*y0)*(x0*y1 - x1*y0 - x0*y3 + x3*y0 + x1*y3 - x3*y1)*(x1*y2 - x2*y1 - x1*y3 + x3*y1 + x2*y3 - x3*y2))/(- x0*x0*x1*y1*y2*y2 + 2*x0*x0*x1*y1*y2*y3 - x0*x0*x1*y1*y3*y3 + x0*x0*x2*y1*y1*y2 - 2*x0*x0*x2*y1*y2*y3 + x0*x0*x2*y2*y3*y3 - 2*x0*x0*x3*y1*y1*y2 + x0*x0*x3*y1*y1*y3 + 2*x0*x0*x3*y1*y2*y2 - x0*x0*x3*y2*y2*y3 + x0*x1*x1*y0*y2*y2 - 2*x0*x1*x1*y0*y2*y3 + x0*x1*x1*y0*y3*y3 - 2*x0*x1*x2*y0*y1*y3 + 2*x0*x1*x2*y0*y2*y3 + 2*x0*x1*x2*y1*y3*y3 - 2*x0*x1*x2*y2*y3*y3 + 2*x0*x1*x3*y0*y1*y2 - 2*x0*x1*x3*y0*y2*y2 - 2*x0*x1*x3*y1*y2*y3 + 2*x0*x1*x3*y2*y2*y3 - x0*x2*x2*y0*y1*y1 + 2*x0*x2*x2*y0*y1*y3 - x0*x2*x2*y0*y3*y3 + 2*x0*x2*x3*y0*y1*y1 - 2*x0*x2*x3*y0*y1*y2 - 2*x0*x2*x3*y1*y1*y3 + 2*x0*x2*x3*y1*y2*y3 - x0*x3*x3*y0*y1*y1 + x0*x3*x3*y0*y2*y2 + 2*x0*x3*x3*y1*y1*y2 - 2*x0*x3*x3*y1*y2*y2 - x1*x1*x2*y0*y0*y2 + 2*x1*x1*x2*y0*y0*y3 - 2*x1*x1*x2*y0*y3*y3 + x1*x1*x2*y2*y3*y3 - x1*x1*x3*y0*y0*y3 + 2*x1*x1*x3*y0*y2*y3 - x1*x1*x3*y2*y2*y3 + x1*x2*x2*y0*y0*y1 - 2*x1*x2*x2*y0*y0*y3 + 2*x1*x2*x2*y0*y3*y3 - x1*x2*x2*y1*y3*y3 - 2*x1*x2*x3*y0*y0*y1 + 2*x1*x2*x3*y0*y0*y2 + 2*x1*x2*x3*y0*y1*y3 - 2*x1*x2*x3*y0*y2*y3 + x1*x3*x3*y0*y0*y1 - 2*x1*x3*x3*y0*y1*y2 + x1*x3*x3*y1*y2*y2 + x2*x2*x3*y0*y0*y3 - 2*x2*x2*x3*y0*y1*y3 + x2*x2*x3*y1*y1*y3 - x2*x3*x3*y0*y0*y2 + 2*x2*x3*x3*y0*y1*y2 - x2*x3*x3*y1*y1*y2);
m10 = -(RES_V*(y0 - y1)*(x0*y2 - x2*y0 - x0*y3 + x3*y0 + x2*y3 - x3*y2)*(x1*y2 - x2*y1 - x1*y3 + x3*y1 + x2*y3 - x3*y2))/(- x0*x0*x1*y1*y2*y2 + 2*x0*x0*x1*y1*y2*y3 - x0*x0*x1*y1*y3*y3 + x0*x0*x2*y1*y1*y2 - 2*x0*x0*x2*y1*y2*y3 + x0*x0*x2*y2*y3*y3 - 2*x0*x0*x3*y1*y1*y2 + x0*x0*x3*y1*y1*y3 + 2*x0*x0*x3*y1*y2*y2 - x0*x0*x3*y2*y2*y3 + x0*x1*x1*y0*y2*y2 - 2*x0*x1*x1*y0*y2*y3 + x0*x1*x1*y0*y3*y3 - 2*x0*x1*x2*y0*y1*y3 + 2*x0*x1*x2*y0*y2*y3 + 2*x0*x1*x2*y1*y3*y3 - 2*x0*x1*x2*y2*y3*y3 + 2*x0*x1*x3*y0*y1*y2 - 2*x0*x1*x3*y0*y2*y2 - 2*x0*x1*x3*y1*y2*y3 + 2*x0*x1*x3*y2*y2*y3 - x0*x2*x2*y0*y1*y1 + 2*x0*x2*x2*y0*y1*y3 - x0*x2*x2*y0*y3*y3 + 2*x0*x2*x3*y0*y1*y1 - 2*x0*x2*x3*y0*y1*y2 - 2*x0*x2*x3*y1*y1*y3 + 2*x0*x2*x3*y1*y2*y3 - x0*x3*x3*y0*y1*y1 + x0*x3*x3*y0*y2*y2 + 2*x0*x3*x3*y1*y1*y2 - 2*x0*x3*x3*y1*y2*y2 - x1*x1*x2*y0*y0*y2 + 2*x1*x1*x2*y0*y0*y3 - 2*x1*x1*x2*y0*y3*y3 + x1*x1*x2*y2*y3*y3 - x1*x1*x3*y0*y0*y3 + 2*x1*x1*x3*y0*y2*y3 - x1*x1*x3*y2*y2*y3 + x1*x2*x2*y0*y0*y1 - 2*x1*x2*x2*y0*y0*y3 + 2*x1*x2*x2*y0*y3*y3 - x1*x2*x2*y1*y3*y3 - 2*x1*x2*x3*y0*y0*y1 + 2*x1*x2*x3*y0*y0*y2 + 2*x1*x2*x3*y0*y1*y3 - 2*x1*x2*x3*y0*y2*y3 + x1*x3*x3*y0*y0*y1 - 2*x1*x3*x3*y0*y1*y2 + x1*x3*x3*y1*y2*y2 + x2*x2*x3*y0*y0*y3 - 2*x2*x2*x3*y0*y1*y3 + x2*x2*x3*y1*y1*y3 - x2*x3*x3*y0*y0*y2 + 2*x2*x3*x3*y0*y1*y2 - x2*x3*x3*y1*y1*y2);
m11 = (RES_V*(x0 - x1)*(x0*y2 - x2*y0 - x0*y3 + x3*y0 + x2*y3 - x3*y2)*(x1*y2 - x2*y1 - x1*y3 + x3*y1 + x2*y3 - x3*y2))/(- x0*x0*x1*y1*y2*y2 + 2*x0*x0*x1*y1*y2*y3 - x0*x0*x1*y1*y3*y3 + x0*x0*x2*y1*y1*y2 - 2*x0*x0*x2*y1*y2*y3 + x0*x0*x2*y2*y3*y3 - 2*x0*x0*x3*y1*y1*y2 + x0*x0*x3*y1*y1*y3 + 2*x0*x0*x3*y1*y2*y2 - x0*x0*x3*y2*y2*y3 + x0*x1*x1*y0*y2*y2 - 2*x0*x1*x1*y0*y2*y3 + x0*x1*x1*y0*y3*y3 - 2*x0*x1*x2*y0*y1*y3 + 2*x0*x1*x2*y0*y2*y3 + 2*x0*x1*x2*y1*y3*y3 - 2*x0*x1*x2*y2*y3*y3 + 2*x0*x1*x3*y0*y1*y2 - 2*x0*x1*x3*y0*y2*y2 - 2*x0*x1*x3*y1*y2*y3 + 2*x0*x1*x3*y2*y2*y3 - x0*x2*x2*y0*y1*y1 + 2*x0*x2*x2*y0*y1*y3 - x0*x2*x2*y0*y3*y3 + 2*x0*x2*x3*y0*y1*y1 - 2*x0*x2*x3*y0*y1*y2 - 2*x0*x2*x3*y1*y1*y3 + 2*x0*x2*x3*y1*y2*y3 - x0*x3*x3*y0*y1*y1 + x0*x3*x3*y0*y2*y2 + 2*x0*x3*x3*y1*y1*y2 - 2*x0*x3*x3*y1*y2*y2 - x1*x1*x2*y0*y0*y2 + 2*x1*x1*x2*y0*y0*y3 - 2*x1*x1*x2*y0*y3*y3 + x1*x1*x2*y2*y3*y3 - x1*x1*x3*y0*y0*y3 + 2*x1*x1*x3*y0*y2*y3 - x1*x1*x3*y2*y2*y3 + x1*x2*x2*y0*y0*y1 - 2*x1*x2*x2*y0*y0*y3 + 2*x1*x2*x2*y0*y3*y3 - x1*x2*x2*y1*y3*y3 - 2*x1*x2*x3*y0*y0*y1 + 2*x1*x2*x3*y0*y0*y2 + 2*x1*x2*x3*y0*y1*y3 - 2*x1*x2*x3*y0*y2*y3 + x1*x3*x3*y0*y0*y1 - 2*x1*x3*x3*y0*y1*y2 + x1*x3*x3*y1*y2*y2 + x2*x2*x3*y0*y0*y3 - 2*x2*x2*x3*y0*y1*y3 + x2*x2*x3*y1*y1*y3 - x2*x3*x3*y0*y0*y2 + 2*x2*x3*x3*y0*y1*y2 - x2*x3*x3*y1*y1*y2);
m12 = -(RES_V*(x0*y1 - x1*y0)*(x0*y2 - x2*y0 - x0*y3 + x3*y0 + x2*y3 - x3*y2)*(x1*y2 - x2*y1 - x1*y3 + x3*y1 + x2*y3 - x3*y2))/(- x0*x0*x1*y1*y2*y2 + 2*x0*x0*x1*y1*y2*y3 - x0*x0*x1*y1*y3*y3 + x0*x0*x2*y1*y1*y2 - 2*x0*x0*x2*y1*y2*y3 + x0*x0*x2*y2*y3*y3 - 2*x0*x0*x3*y1*y1*y2 + x0*x0*x3*y1*y1*y3 + 2*x0*x0*x3*y1*y2*y2 - x0*x0*x3*y2*y2*y3 + x0*x1*x1*y0*y2*y2 - 2*x0*x1*x1*y0*y2*y3 + x0*x1*x1*y0*y3*y3 - 2*x0*x1*x2*y0*y1*y3 + 2*x0*x1*x2*y0*y2*y3 + 2*x0*x1*x2*y1*y3*y3 - 2*x0*x1*x2*y2*y3*y3 + 2*x0*x1*x3*y0*y1*y2 - 2*x0*x1*x3*y0*y2*y2 - 2*x0*x1*x3*y1*y2*y3 + 2*x0*x1*x3*y2*y2*y3 - x0*x2*x2*y0*y1*y1 + 2*x0*x2*x2*y0*y1*y3 - x0*x2*x2*y0*y3*y3 + 2*x0*x2*x3*y0*y1*y1 - 2*x0*x2*x3*y0*y1*y2 - 2*x0*x2*x3*y1*y1*y3 + 2*x0*x2*x3*y1*y2*y3 - x0*x3*x3*y0*y1*y1 + x0*x3*x3*y0*y2*y2 + 2*x0*x3*x3*y1*y1*y2 - 2*x0*x3*x3*y1*y2*y2 - x1*x1*x2*y0*y0*y2 + 2*x1*x1*x2*y0*y0*y3 - 2*x1*x1*x2*y0*y3*y3 + x1*x1*x2*y2*y3*y3 - x1*x1*x3*y0*y0*y3 + 2*x1*x1*x3*y0*y2*y3 - x1*x1*x3*y2*y2*y3 + x1*x2*x2*y0*y0*y1 - 2*x1*x2*x2*y0*y0*y3 + 2*x1*x2*x2*y0*y3*y3 - x1*x2*x2*y1*y3*y3 - 2*x1*x2*x3*y0*y0*y1 + 2*x1*x2*x3*y0*y0*y2 + 2*x1*x2*x3*y0*y1*y3 - 2*x1*x2*x3*y0*y2*y3 + x1*x3*x3*y0*y0*y1 - 2*x1*x3*x3*y0*y1*y2 + x1*x3*x3*y1*y2*y2 + x2*x2*x3*y0*y0*y3 - 2*x2*x2*x3*y0*y1*y3 + x2*x2*x3*y1*y1*y3 - x2*x3*x3*y0*y0*y2 + 2*x2*x3*x3*y0*y1*y2 - x2*x3*x3*y1*y1*y2);
Используя m00, m01, m02, m10, m11 и m12, я построил матрицу M. Я пропустил m20, m21 и m22, потому что они не влияют на результат x и y.
Наконец, я использовал эту матрицу M для сдвига координат мяча:
x_shifted = m00*x + m01*y + m02;
y_shifted = m10*x + m11*y + m12;
Что основано на этом:
Как видите, решение, созданное Matlab, приводит к очень длинным уравнениям. Случайно я обнаружил, что когда вы меняете местами xi на ui и yi на vi в матрице A, вы получите обратную матрицу преобразования M для m00, m01, m02, m10, m11, m12, но коэффициенты вычисляются с помощью более коротких уравнений.
/ 0 0 1 0 0 0 0 0 \ /m00\ /x0\
| RES_H 0 1 0 0 0 -RES_H*x1 0 | |m01| |x1|
| 0 RES_V 1 0 0 0 0 -RES_V*x2 | |m02| |x2|
| RES_H RES_V 1 0 0 0 -RES_H*x3 -RES_V*x3 |.|m10|=|x3|
| 0 0 0 0 0 1 0 0 | |m11| |y0|
| 0 0 0 RES_H 0 1 -RES_H*y1 0 | |m12| |y1|
| 0 0 0 0 RES_V 1 0 -RES_V*y2 | |m20| |y2|
\ 0 0 0 RES_H RES_V 1 -RES_H*y3 -RES_V*y3 / \m21/ \y3/
Если вы позволите Matlab решить эту задачу таким же образом, вы получите:
m00 = (x0*x2*y1 - x1*x2*y0 - x0*x3*y1 + x1*x3*y0 - x0*x2*y3 + x0*x3*y2 + x1*x2*y3 - x1*x3*y2)/(RES_H*(x1*y2 - x2*y1 - x1*y3 + x3*y1 + x2*y3 - x3*y2));
m01 = -(x0*x1*y2 - x1*x2*y0 - x0*x1*y3 + x0*x3*y1 - x0*x3*y2 + x2*x3*y0 + x1*x2*y3 - x2*x3*y1)/(RES_V*(x1*y2 - x2*y1 - x1*y3 + x3*y1 + x2*y3 - x3*y2));
m02 = x0;
m10 = (x0*y1*y2 - x1*y0*y2 - x0*y1*y3 + x1*y0*y3 - x2*y0*y3 + x3*y0*y2 + x2*y1*y3 - x3*y1*y2)/(RES_H*(x1*y2 - x2*y1 - x1*y3 + x3*y1 + x2*y3 - x3*y2));
m11 = -(x0*y1*y2 - x2*y0*y1 - x1*y0*y3 + x3*y0*y1 - x0*y2*y3 + x2*y0*y3 + x1*y2*y3 - x3*y1*y2)/(RES_V*(x1*y2 - x2*y1 - x1*y3 + x3*y1 + x2*y3 - x3*y2));
m12 = y0;
m20 = (x0*y2 - x2*y0 - x0*y3 - x1*y2 + x2*y1 + x3*y0 + x1*y3 - x3*y1)/(RES_H*(x1*y2 - x2*y1 - x1*y3 + x3*y1 + x2*y3 - x3*y2));
m21 = -(x0*y1 - x1*y0 - x0*y3 + x1*y2 - x2*y1 + x3*y0 + x2*y3 - x3*y2)/(RES_V*(x1*y2 - x2*y1 - x1*y3 + x3*y1 + x2*y3 - x3*y2));
m22 = 1.0;
Когда вы помещаете эти коэффициенты в матрицу и инвертируете эту матрицу, вы получите те же результаты для m00, m01, m02, m10, m11, m12, что и для первого метода.
Я использовал программу, которую нашел здесь, чтобы инвертировать матрицу: https://codingtech2017.wordpress.com/2017/05/03/c-program-to-inverse-a-matrix3x3/
person
Roy Meijer
schedule
24.02.2021