| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- using System;
- using System.Diagnostics;
- using o0.Geometry2D.Float;
- // 其实这个类内部是用Double计算的
- namespace ZIM
- {
- // 来源 https://web.archive.org/web/20150222120106/xenia.media.mit.edu/~cwren/interpolator/
- public class ZIMPerspectiveTransform
- {
- // 变换矩阵
- double[,] H;
- double[,] InverseH;
- public ZIMPerspectiveTransform(OrdinalQuadrilateral src, OrdinalQuadrilateral dst)
- {
- // 该算法点序为 左下角开始 顺时针
- double[] X = new double[4] { src.A.x, src.C.x, src.D.x, src.B.x };
- double[] Y = new double[4] { src.A.y, src.C.y, src.D.y, src.B.y };
- double[] Xp = new double[4] { dst.A.x, dst.C.x, dst.D.x, dst.B.x };
- double[] Yp = new double[4] { dst.A.y, dst.C.y, dst.D.y, dst.B.y };
- TransformEstimate(X, Y, Xp, Yp);
- //UnityEngine.Debug.Log(H.ToJson(true));
- //UnityEngine.Debug.Log(H[0, 0]);
- //UnityEngine.Debug.Log(H[0, 1]);
- //UnityEngine.Debug.Log(H[0, 2]);
- }
- //public Vector Transform(Vector v)
- //{
- // var result = Transform(v.x, v.y);
- // return new Vector((float)result.x, (float)result.y);
- //}
- public (int x, int y) TransformRound(int x, int y)
- {
- var result = Transform((double)x, (double)y);
- return ((int)Math.Round(result.x), (int)Math.Round(result.y));
- }
- public (float x, float y) Transform(float x, float y)
- {
- var result = Transform((double)x, (double)y);
- return ((float)result.x, (float)result.y);
- }
- public (double x, double y) Transform(double x, double y)
- {
- double t1 = H[0, 0] * x + H[0, 1] * y + H[0, 2];
- double t2 = H[1, 0] * x + H[1, 1] * y + H[1, 2];
- double t3 = H[2, 0] * x + H[2, 1] * y + H[2, 2];
- return (t1 / t3, t2 / t3);
- }
- public (float x, float y) TransformInverse(float x, float y)
- {
- var result = TransformInverse((double)x, (double)y);
- return ((float)result.x, (float)result.y);
- }
- public (double x, double y) TransformInverse(double x, double y)
- {
- double t1 = InverseH[0, 0] * x + InverseH[0, 1] * y + InverseH[0, 2];
- double t2 = InverseH[1, 0] * x + InverseH[1, 1] * y + InverseH[1, 2];
- double t3 = InverseH[2, 0] * x + InverseH[2, 1] * y + InverseH[2, 2];
- return (t1 / t3, t2 / t3);
- }
- // Calculate matrix transform
- void TransformEstimate(double[] X, double[] Y, double[] Xp, double[] Yp)
- {
- //double[] Xp = { 0, 0, 1280, 1280 };
- //double[] Yp = { 0, 720, 720, 0 };
- double[,] B = new double[8, 8];
- double[,] D = new double[8, 1];
- for (int i = 0; i < 4; i++)
- {
- B[i, 0] = X[i];
- B[i, 1] = Y[i];
- B[i, 2] = 1;
- B[i, 6] = -X[i] * Xp[i];
- B[i, 7] = -Y[i] * Xp[i];
- B[i + 4, 3] = X[i];
- B[i + 4, 4] = Y[i];
- B[i + 4, 5] = 1;
- B[i + 4, 6] = -X[i] * Yp[i];
- B[i + 4, 7] = -Y[i] * Yp[i];
- }
- for (int i = 0; i < 4; i++)
- {
- D[i, 0] = Xp[i];
- D[i + 4, 0] = Yp[i];
- }
- double[,] BTranspose = TransposeMatrix(B);
- double[,] l = MatrixMultiply(MatrixMultiply(MatrixInverse(MatrixMultiply(BTranspose, B)), BTranspose), D); // l 是8行1列的矩阵
- H = new double[3, 3] { { l[0, 0], l[1, 0], l[2, 0] }, { l[3, 0], l[4, 0], l[5, 0] }, { l[6, 0], l[7, 0], 1 } };
- InverseH = MatrixInverse(H);
- // 测试代码
- //var x1 = X[2];
- //var y1 = Y[2];
- //var x2 = X[0];
- //var y2 = Y[0];
- //// Plot the points and their transformed coordinates
- //UnityEngine.Debug.Log("Plotting the points and their transformed coordinates...");
- //for (double u = 0; u <= 1; u += 0.1)
- //{
- // double x = u * x1 + (1 - u) * x2;
- // double y = u * y1 + (1 - u) * y2;
- // UnityEngine.Debug.Log($"Point ({x}, {y})");
- // double t1 = H[0, 0] * x + H[0, 1] * y + H[0, 2];
- // double t2 = H[1, 0] * x + H[1, 1] * y + H[1, 2];
- // double t3 = H[2, 0] * x + H[2, 1] * y + H[2, 2];
- // double tX = t1 / t3;
- // double tY = t2 / t3;
- // UnityEngine.Debug.Log($"Transformed point ({tX}, {tY})");
- //}
- }
- static double[,] TransposeMatrix(double[,] matrix)
- {
- int rows = matrix.GetLength(0);
- int cols = matrix.GetLength(1);
- double[,] result = new double[cols, rows];
- for (int i = 0; i < rows; i++)
- {
- for (int j = 0; j < cols; j++)
- {
- result[j, i] = matrix[i, j];
- }
- }
- return result;
- }
- static double[,] ReshapeMatrix(double[,] matrix, int rows, int cols)
- {
- int originalRows = matrix.GetLength(0);
- int originalCols = matrix.GetLength(1);
- if (originalRows * originalCols != rows * cols)
- {
- throw new Exception("Invalid reshape dimensions");
- }
- double[,] result = new double[rows, cols];
- int rowIndex = 0;
- int colIndex = 0;
- for (int i = 0; i < originalRows; i++)
- {
- for (int j = 0; j < originalCols; j++)
- {
- result[rowIndex, colIndex] = matrix[i, j];
- colIndex++;
- if (colIndex == cols)
- {
- colIndex = 0;
- rowIndex++;
- }
- }
- }
- return result;
- }
- static double[,] ReshapeMatrix(double[] array, int rows, int cols)
- {
- double[,] result = new double[rows, cols];
- int index = 0;
- for (int j = 0; j < cols; j++)
- {
- for (int i = 0; i < rows; i++)
- {
- result[i, j] = array[index];
- index++;
- }
- }
- return result;
- }
- static double[,] MatrixMultiply(double[,] matrix1, double[,] matrix2)
- {
- int rows1 = matrix1.GetLength(0);
- int cols1 = matrix1.GetLength(1);
- int rows2 = matrix2.GetLength(0);
- int cols2 = matrix2.GetLength(1);
- if (cols1 != rows2)
- {
- throw new Exception("Invalid matrix dimensions");
- }
- double[,] result = new double[rows1, cols2];
- for (int i = 0; i < rows1; i++)
- {
- for (int j = 0; j < cols2; j++)
- {
- for (int k = 0; k < cols1; k++)
- {
- result[i, j] += matrix1[i, k] * matrix2[k, j];
- }
- }
- }
- return result;
- }
- static double[,] MatrixInverse(double[,] matrix)
- {
- int n = matrix.GetLength(0);
- double[,] augmentedMatrix = new double[n, 2 * n];
- for (int i = 0; i < n; i++)
- {
- for (int j = 0; j < n; j++)
- {
- augmentedMatrix[i, j] = matrix[i, j];
- }
- augmentedMatrix[i, i + n] = 1;
- }
- for (int i = 0; i < n; i++)
- {
- double pivot = augmentedMatrix[i, i];
- for (int j = 0; j < 2 * n; j++)
- {
- augmentedMatrix[i, j] /= pivot;
- }
- for (int k = 0; k < n; k++)
- {
- if (k != i)
- {
- double factor = augmentedMatrix[k, i];
- for (int j = 0; j < 2 * n; j++)
- {
- augmentedMatrix[k, j] -= factor * augmentedMatrix[i, j];
- }
- }
- }
- }
- double[,] inverseMatrix = new double[n, n];
- for (int i = 0; i < n; i++)
- {
- for (int j = 0; j < n; j++)
- {
- inverseMatrix[i, j] = augmentedMatrix[i, j + n];
- }
- }
- return inverseMatrix;
- }
- }
- }
|