PerspectiveTransform.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. using System;
  2. using System.Diagnostics;
  3. // 其实这个类内部是用Double计算的
  4. namespace o0.Geometry2D.Float
  5. {
  6. // 来源 https://web.archive.org/web/20150222120106/xenia.media.mit.edu/~cwren/interpolator/
  7. public class PerspectiveTransform
  8. {
  9. // 变换矩阵
  10. double[,] H;
  11. double[,] InverseH;
  12. public PerspectiveTransform(Quadrilateral src, Quadrilateral dst)
  13. {
  14. // 该算法点序为 左下角开始 顺时针
  15. double[] X = new double[4] { src.A.x, src.C.x, src.D.x, src.B.x };
  16. double[] Y = new double[4] { src.A.y, src.C.y, src.D.y, src.B.y };
  17. double[] Xp = new double[4] { dst.A.x, dst.C.x, dst.D.x, dst.B.x };
  18. double[] Yp = new double[4] { dst.A.y, dst.C.y, dst.D.y, dst.B.y };
  19. TransformEstimate(X, Y, Xp, Yp);
  20. //UnityEngine.Debug.Log(H.ToJson(true));
  21. //UnityEngine.Debug.Log(H[0, 0]);
  22. //UnityEngine.Debug.Log(H[0, 1]);
  23. //UnityEngine.Debug.Log(H[0, 2]);
  24. }
  25. //public Vector Transform(Vector v)
  26. //{
  27. // var result = Transform(v.x, v.y);
  28. // return new Vector((float)result.x, (float)result.y);
  29. //}
  30. public (int x, int y) TransformRound(int x, int y)
  31. {
  32. var result = Transform((double)x, (double)y);
  33. return ((int)Math.Round(result.x), (int)Math.Round(result.y));
  34. }
  35. public (float x, float y) Transform(float x, float y)
  36. {
  37. var result = Transform((double)x, (double)y);
  38. return ((float)result.x, (float)result.y);
  39. }
  40. public (double x, double y) Transform(double x, double y)
  41. {
  42. double t1 = H[0, 0] * x + H[0, 1] * y + H[0, 2];
  43. double t2 = H[1, 0] * x + H[1, 1] * y + H[1, 2];
  44. double t3 = H[2, 0] * x + H[2, 1] * y + H[2, 2];
  45. return (t1 / t3, t2 / t3);
  46. }
  47. public (float x, float y) TransformInverse(float x, float y)
  48. {
  49. var result = TransformInverse((double)x, (double)y);
  50. return ((float)result.x, (float)result.y);
  51. }
  52. public (double x, double y) TransformInverse(double x, double y)
  53. {
  54. double t1 = InverseH[0, 0] * x + InverseH[0, 1] * y + InverseH[0, 2];
  55. double t2 = InverseH[1, 0] * x + InverseH[1, 1] * y + InverseH[1, 2];
  56. double t3 = InverseH[2, 0] * x + InverseH[2, 1] * y + InverseH[2, 2];
  57. return (t1 / t3, t2 / t3);
  58. }
  59. // Calculate matrix transform
  60. void TransformEstimate(double[] X, double[] Y, double[] Xp, double[] Yp)
  61. {
  62. //double[] Xp = { 0, 0, 1280, 1280 };
  63. //double[] Yp = { 0, 720, 720, 0 };
  64. double[,] B = new double[8, 8];
  65. double[,] D = new double[8, 1];
  66. for (int i = 0; i < 4; i++)
  67. {
  68. B[i, 0] = X[i];
  69. B[i, 1] = Y[i];
  70. B[i, 2] = 1;
  71. B[i, 6] = -X[i] * Xp[i];
  72. B[i, 7] = -Y[i] * Xp[i];
  73. B[i + 4, 3] = X[i];
  74. B[i + 4, 4] = Y[i];
  75. B[i + 4, 5] = 1;
  76. B[i + 4, 6] = -X[i] * Yp[i];
  77. B[i + 4, 7] = -Y[i] * Yp[i];
  78. }
  79. for (int i = 0; i < 4; i++)
  80. {
  81. D[i, 0] = Xp[i];
  82. D[i + 4, 0] = Yp[i];
  83. }
  84. double[,] BTranspose = TransposeMatrix(B);
  85. double[,] l = MatrixMultiply(MatrixMultiply(MatrixInverse(MatrixMultiply(BTranspose, B)), BTranspose), D); // l 是8行1列的矩阵
  86. 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 } };
  87. InverseH = MatrixInverse(H);
  88. // 测试代码
  89. //var x1 = X[2];
  90. //var y1 = Y[2];
  91. //var x2 = X[0];
  92. //var y2 = Y[0];
  93. //// Plot the points and their transformed coordinates
  94. //UnityEngine.Debug.Log("Plotting the points and their transformed coordinates...");
  95. //for (double u = 0; u <= 1; u += 0.1)
  96. //{
  97. // double x = u * x1 + (1 - u) * x2;
  98. // double y = u * y1 + (1 - u) * y2;
  99. // UnityEngine.Debug.Log($"Point ({x}, {y})");
  100. // double t1 = H[0, 0] * x + H[0, 1] * y + H[0, 2];
  101. // double t2 = H[1, 0] * x + H[1, 1] * y + H[1, 2];
  102. // double t3 = H[2, 0] * x + H[2, 1] * y + H[2, 2];
  103. // double tX = t1 / t3;
  104. // double tY = t2 / t3;
  105. // UnityEngine.Debug.Log($"Transformed point ({tX}, {tY})");
  106. //}
  107. }
  108. static double[,] TransposeMatrix(double[,] matrix)
  109. {
  110. int rows = matrix.GetLength(0);
  111. int cols = matrix.GetLength(1);
  112. double[,] result = new double[cols, rows];
  113. for (int i = 0; i < rows; i++)
  114. {
  115. for (int j = 0; j < cols; j++)
  116. {
  117. result[j, i] = matrix[i, j];
  118. }
  119. }
  120. return result;
  121. }
  122. static double[,] ReshapeMatrix(double[,] matrix, int rows, int cols)
  123. {
  124. int originalRows = matrix.GetLength(0);
  125. int originalCols = matrix.GetLength(1);
  126. if (originalRows * originalCols != rows * cols)
  127. {
  128. throw new Exception("Invalid reshape dimensions");
  129. }
  130. double[,] result = new double[rows, cols];
  131. int rowIndex = 0;
  132. int colIndex = 0;
  133. for (int i = 0; i < originalRows; i++)
  134. {
  135. for (int j = 0; j < originalCols; j++)
  136. {
  137. result[rowIndex, colIndex] = matrix[i, j];
  138. colIndex++;
  139. if (colIndex == cols)
  140. {
  141. colIndex = 0;
  142. rowIndex++;
  143. }
  144. }
  145. }
  146. return result;
  147. }
  148. static double[,] ReshapeMatrix(double[] array, int rows, int cols)
  149. {
  150. double[,] result = new double[rows, cols];
  151. int index = 0;
  152. for (int j = 0; j < cols; j++)
  153. {
  154. for (int i = 0; i < rows; i++)
  155. {
  156. result[i, j] = array[index];
  157. index++;
  158. }
  159. }
  160. return result;
  161. }
  162. static double[,] MatrixMultiply(double[,] matrix1, double[,] matrix2)
  163. {
  164. int rows1 = matrix1.GetLength(0);
  165. int cols1 = matrix1.GetLength(1);
  166. int rows2 = matrix2.GetLength(0);
  167. int cols2 = matrix2.GetLength(1);
  168. if (cols1 != rows2)
  169. {
  170. throw new Exception("Invalid matrix dimensions");
  171. }
  172. double[,] result = new double[rows1, cols2];
  173. for (int i = 0; i < rows1; i++)
  174. {
  175. for (int j = 0; j < cols2; j++)
  176. {
  177. for (int k = 0; k < cols1; k++)
  178. {
  179. result[i, j] += matrix1[i, k] * matrix2[k, j];
  180. }
  181. }
  182. }
  183. return result;
  184. }
  185. static double[,] MatrixInverse(double[,] matrix)
  186. {
  187. int n = matrix.GetLength(0);
  188. double[,] augmentedMatrix = new double[n, 2 * n];
  189. for (int i = 0; i < n; i++)
  190. {
  191. for (int j = 0; j < n; j++)
  192. {
  193. augmentedMatrix[i, j] = matrix[i, j];
  194. }
  195. augmentedMatrix[i, i + n] = 1;
  196. }
  197. for (int i = 0; i < n; i++)
  198. {
  199. double pivot = augmentedMatrix[i, i];
  200. for (int j = 0; j < 2 * n; j++)
  201. {
  202. augmentedMatrix[i, j] /= pivot;
  203. }
  204. for (int k = 0; k < n; k++)
  205. {
  206. if (k != i)
  207. {
  208. double factor = augmentedMatrix[k, i];
  209. for (int j = 0; j < 2 * n; j++)
  210. {
  211. augmentedMatrix[k, j] -= factor * augmentedMatrix[i, j];
  212. }
  213. }
  214. }
  215. }
  216. double[,] inverseMatrix = new double[n, n];
  217. for (int i = 0; i < n; i++)
  218. {
  219. for (int j = 0; j < n; j++)
  220. {
  221. inverseMatrix[i, j] = augmentedMatrix[i, j + n];
  222. }
  223. }
  224. return inverseMatrix;
  225. }
  226. }
  227. }