PerspectiveTransform.cs 8.6 KB

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