MatrixH.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. namespace VisualMath.Accord.Imaging
  2. {
  3. using System;
  4. using System.Drawing;
  5. /// <summary>
  6. /// Encapsulates a 3-by-3 general transformation matrix that represents
  7. /// a (possibly) non-linear transform.
  8. /// </summary>
  9. /// <remarks>
  10. /// <para>
  11. /// Linear transformations are not the only ones that can be represented by
  12. /// matrices. Using homogeneous coordinates, both affine transformations and
  13. /// perspective projections on R^n can be represented as linear transformations
  14. /// on R^n+1 (that is, n+1-dimensional real projective space).</para>
  15. /// <para>
  16. /// The general transformation matrix has 8 degrees of freedom, as the last element is just a scale parameter.</para>
  17. /// </remarks>
  18. ///
  19. [Serializable]
  20. public class MatrixH
  21. {
  22. private float[] elements;
  23. /// <summary>
  24. /// Creates a new projective matrix.
  25. /// </summary>
  26. public MatrixH()
  27. {
  28. // Start as the identity matrix
  29. this.elements = new float[] { 1, 0, 0, 0, 1, 0, 0, 0 };
  30. }
  31. /// <summary>
  32. /// Creates a new projective matrix.
  33. /// </summary>
  34. public MatrixH(float m11, float m12, float m13,
  35. float m21, float m22, float m23,
  36. float m31, float m32)
  37. {
  38. this.elements = new float[8];
  39. this.elements[0] = m11; this.elements[1] = m12; this.elements[2] = m13;
  40. this.elements[3] = m21; this.elements[4] = m22; this.elements[5] = m23;
  41. this.elements[6] = m31; this.elements[7] = m32;
  42. }
  43. /// <summary>
  44. /// Creates a new projective matrix.
  45. /// </summary>
  46. public MatrixH(float m11, float m12, float m13,
  47. float m21, float m22, float m23,
  48. float m31, float m32, float m33)
  49. : this(m11, m12, m13, m21, m22, m23, m31, m32)
  50. {
  51. for (int i = 0; i < 8; i++)
  52. elements[i] /= m33;
  53. }
  54. /// <summary>
  55. /// Creates a new projective matrix.
  56. /// </summary>
  57. public MatrixH(double[,] H)
  58. {
  59. this.elements = new float[8];
  60. for (int i = 0, k = 0; i < 3; i++)
  61. for (int j = 0; j < 3 && k < 8; j++, k++)
  62. this.elements[k] = (float)(H[i, j] / H[2, 2]);
  63. }
  64. /// <summary>
  65. /// Gets the elements of this matrix.
  66. /// </summary>
  67. public float[] Elements
  68. {
  69. get { return elements; }
  70. }
  71. /// <summary>
  72. /// Gets the offset x
  73. /// </summary>
  74. public float OffsetX
  75. {
  76. get { return elements[2]; }
  77. }
  78. /// <summary>
  79. /// Gets the offset y
  80. /// </summary>
  81. public float OffsetY
  82. {
  83. get { return elements[5]; }
  84. }
  85. /// <summary>
  86. /// Gets whether this matrix is invertible.
  87. /// </summary>
  88. public bool IsInvertible
  89. {
  90. get
  91. {
  92. float det = elements[0] * (elements[4] - elements[5] * elements[7])
  93. - elements[1] * (elements[3] - elements[5] * elements[6])
  94. + elements[2] * (elements[3] * elements[7] - elements[4] * elements[6]);
  95. return det > 0;
  96. }
  97. }
  98. /// <summary>
  99. /// Gets whether this is an Affine transformation matrix.
  100. /// </summary>
  101. public bool IsAffine
  102. {
  103. get { return (elements[6] == 0 && elements[7] == 0); }
  104. }
  105. /// <summary>
  106. /// Gets whether this is the identity transformation.
  107. /// </summary>
  108. public bool IsIdentity
  109. {
  110. get
  111. {
  112. return
  113. elements[0] == 1 && elements[1] == 0 && elements[2] == 0 &&
  114. elements[3] == 0 && elements[4] == 1 && elements[5] == 0 &&
  115. elements[6] == 0 && elements[7] == 0;
  116. }
  117. }
  118. /// <summary>
  119. /// Resets this matrix to be the identity.
  120. /// </summary>
  121. public void Reset()
  122. {
  123. elements[0] = 1; elements[1] = 0; elements[2] = 0;
  124. elements[3] = 0; elements[4] = 1; elements[5] = 0;
  125. elements[6] = 0; elements[7] = 0;
  126. }
  127. /// <summary>
  128. /// Returns the inverse matrix, if this matrix is invertible.
  129. /// </summary>
  130. public MatrixH Inverse()
  131. {
  132. // m = 1 / [a(ei-fh) - b(di-fg) + c(dh-eg)]
  133. //
  134. // (ei-fh) (ch-bi) (bf-ce)
  135. // inv(A) = m x (fg-di) (ai-cg) (cd-af)
  136. // (dh-eg) (bg-ah) (ae-bd)
  137. //
  138. float a = this.elements[0], b = this.elements[1], c = this.elements[2];
  139. float d = this.elements[3], e = this.elements[4], f = this.elements[5];
  140. float g = this.elements[6], h = this.elements[7];
  141. float m = 1f / (a * (e - f * h) - b * (d - f * g) + c * (d * h - e * g));
  142. float na = m * (e - f * h);
  143. float nb = m * (c * h - b);
  144. float nc = m * (b * f - c * e);
  145. float nd = m * (f * g - d);
  146. float ne = m * (a - c * g);
  147. float nf = m * (c * d - a * f);
  148. float ng = m * (d * h - e * g);
  149. float nh = m * (b * g - a * h);
  150. float nj = m * (a * e - b * d);
  151. return new MatrixH(na, nb, nc, nd, ne, nf, ng, nh, nj);
  152. }
  153. /// <summary>
  154. /// Transforms the given points using this transformation matrix.
  155. /// </summary>
  156. public PointH[] TransformPoints(params PointH[] points)
  157. {
  158. PointH[] r = new PointH[points.Length];
  159. for (int j = 0; j < points.Length; j++)
  160. {
  161. r[j].X = elements[0] * points[j].X + elements[1] * points[j].Y + elements[2] * points[j].W;
  162. r[j].Y = elements[3] * points[j].X + elements[4] * points[j].Y + elements[5] * points[j].W;
  163. r[j].W = elements[6] * points[j].X + elements[7] * points[j].Y + points[j].W;
  164. }
  165. return r;
  166. }
  167. /// <summary>
  168. /// Transforms the given points using this transformation matrix.
  169. /// </summary>
  170. public PointF[] TransformPoints(params PointF[] points)
  171. {
  172. PointF[] r = new PointF[points.Length];
  173. for (int j = 0; j < points.Length; j++)
  174. {
  175. float w = elements[6] * points[j].X + elements[7] * points[j].Y + 1f;
  176. r[j].X = (elements[0] * points[j].X + elements[1] * points[j].Y + elements[2]) / w;
  177. r[j].Y = (elements[3] * points[j].X + elements[4] * points[j].Y + elements[5]) / w;
  178. }
  179. return r;
  180. }
  181. /// <summary>
  182. /// Multiplies this matrix, returning a new matrix as result.
  183. /// </summary>
  184. public MatrixH Multiply(MatrixH matrix)
  185. {
  186. float na = elements[0] * matrix.elements[0] + elements[1] * matrix.elements[3] + elements[2] * matrix.elements[6];
  187. float nb = elements[0] * matrix.elements[1] + elements[1] * matrix.elements[4] + elements[2] * matrix.elements[7];
  188. float nc = elements[0] * matrix.elements[2] + elements[1] * matrix.elements[5] + elements[2];
  189. float nd = elements[3] * matrix.elements[0] + elements[4] * matrix.elements[3] + elements[5] * matrix.elements[6];
  190. float ne = elements[3] * matrix.elements[1] + elements[4] * matrix.elements[4] + elements[5] * matrix.elements[7];
  191. float nf = elements[3] * matrix.elements[2] + elements[4] * matrix.elements[5] + elements[5];
  192. float ng = elements[6] * matrix.elements[0] + elements[7] * matrix.elements[3] + matrix.elements[6];
  193. float nh = elements[6] * matrix.elements[1] + elements[7] * matrix.elements[4] + matrix.elements[7];
  194. float ni = elements[6] * matrix.elements[2] + elements[7] * matrix.elements[5] + 1f;
  195. return new MatrixH(na, nb, nc, nd, ne, nf, ng, nh, ni);
  196. }
  197. /// <summary>
  198. /// Compares two objects for equality.
  199. /// </summary>
  200. public override bool Equals(object obj)
  201. {
  202. if (obj is MatrixH)
  203. {
  204. MatrixH m = obj as MatrixH;
  205. return this == m;
  206. }
  207. else
  208. {
  209. return false;
  210. }
  211. }
  212. /// <summary>
  213. /// Returns the hash code for this instance.
  214. /// </summary>
  215. public override int GetHashCode()
  216. {
  217. return elements.GetHashCode();
  218. }
  219. /// <summary>
  220. /// Double[,] conversion.
  221. /// </summary>
  222. public static explicit operator double[,](MatrixH matrix)
  223. {
  224. return new double[,]
  225. {
  226. { matrix.elements[0], matrix.elements[1], matrix.elements[2] },
  227. { matrix.elements[3], matrix.elements[4], matrix.elements[5] },
  228. { matrix.elements[6], matrix.elements[7], 1.0 },
  229. };
  230. }
  231. /// <summary>
  232. /// Single[,] conversion.
  233. /// </summary>
  234. public static explicit operator float[,](MatrixH matrix)
  235. {
  236. return new float[,]
  237. {
  238. { matrix.elements[0], matrix.elements[1], matrix.elements[2] },
  239. { matrix.elements[3], matrix.elements[4], matrix.elements[5] },
  240. { matrix.elements[6], matrix.elements[7], 1.0f },
  241. };
  242. }
  243. /// <summary>
  244. /// Matrix multiplication.
  245. /// </summary>
  246. public static MatrixH operator *(MatrixH matrix1, MatrixH matrix2)
  247. {
  248. return matrix1.Multiply(matrix2);
  249. }
  250. /// <summary>
  251. /// Equality
  252. /// </summary>
  253. public static bool operator ==(MatrixH a, MatrixH b)
  254. {
  255. for (int i = 0; i < 8; i++)
  256. if (a.elements[i] != b.elements[i])
  257. return false;
  258. return true;
  259. }
  260. /// <summary>
  261. /// Inequality
  262. /// </summary>
  263. public static bool operator !=(MatrixH a, MatrixH b)
  264. {
  265. for (int i = 0; i < 8; i++)
  266. if (a.elements[i] == b.elements[i])
  267. return true;
  268. return false;
  269. }
  270. }
  271. }