matlab_cp2tform.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. import numpy as np
  2. from numpy.linalg import inv, lstsq
  3. from numpy.linalg import matrix_rank as rank
  4. from numpy.linalg import norm
  5. class MatlabCp2tormException(Exception):
  6. def __str__(self):
  7. return "In File {}:{}".format(__file__, super.__str__(self))
  8. def tformfwd(trans, uv):
  9. """
  10. Function:
  11. ----------
  12. apply affine transform 'trans' to uv
  13. Parameters:
  14. ----------
  15. @trans: 3x3 np.array
  16. transform matrix
  17. @uv: Kx2 np.array
  18. each row is a pair of coordinates (x, y)
  19. Returns:
  20. ----------
  21. @xy: Kx2 np.array
  22. each row is a pair of transformed coordinates (x, y)
  23. """
  24. uv = np.hstack((uv, np.ones((uv.shape[0], 1))))
  25. xy = np.dot(uv, trans)
  26. xy = xy[:, 0:-1]
  27. return xy
  28. def tforminv(trans, uv):
  29. """
  30. Function:
  31. ----------
  32. apply the inverse of affine transform 'trans' to uv
  33. Parameters:
  34. ----------
  35. @trans: 3x3 np.array
  36. transform matrix
  37. @uv: Kx2 np.array
  38. each row is a pair of coordinates (x, y)
  39. Returns:
  40. ----------
  41. @xy: Kx2 np.array
  42. each row is a pair of inverse-transformed coordinates (x, y)
  43. """
  44. Tinv = inv(trans)
  45. xy = tformfwd(Tinv, uv)
  46. return xy
  47. def findNonreflectiveSimilarity(uv, xy, options=None):
  48. options = {"K": 2}
  49. K = options["K"]
  50. M = xy.shape[0]
  51. x = xy[:, 0].reshape((-1, 1)) # use reshape to keep a column vector
  52. y = xy[:, 1].reshape((-1, 1)) # use reshape to keep a column vector
  53. tmp1 = np.hstack((x, y, np.ones((M, 1)), np.zeros((M, 1))))
  54. tmp2 = np.hstack((y, -x, np.zeros((M, 1)), np.ones((M, 1))))
  55. X = np.vstack((tmp1, tmp2))
  56. u = uv[:, 0].reshape((-1, 1)) # use reshape to keep a column vector
  57. v = uv[:, 1].reshape((-1, 1)) # use reshape to keep a column vector
  58. U = np.vstack((u, v))
  59. # We know that X * r = U
  60. if rank(X) >= 2 * K:
  61. r, _, _, _ = lstsq(X, U, rcond=-1)
  62. r = np.squeeze(r)
  63. else:
  64. raise Exception("cp2tform:twoUniquePointsReq")
  65. sc = r[0]
  66. ss = r[1]
  67. tx = r[2]
  68. ty = r[3]
  69. Tinv = np.array([[sc, -ss, 0], [ss, sc, 0], [tx, ty, 1]])
  70. T = inv(Tinv)
  71. T[:, 2] = np.array([0, 0, 1])
  72. return T, Tinv
  73. def findSimilarity(uv, xy, options=None):
  74. options = {"K": 2}
  75. # uv = np.array(uv)
  76. # xy = np.array(xy)
  77. # Solve for trans1
  78. trans1, trans1_inv = findNonreflectiveSimilarity(uv, xy, options)
  79. # Solve for trans2
  80. # manually reflect the xy data across the Y-axis
  81. xyR = xy
  82. xyR[:, 0] = -1 * xyR[:, 0]
  83. trans2r, trans2r_inv = findNonreflectiveSimilarity(uv, xyR, options)
  84. # manually reflect the tform to undo the reflection done on xyR
  85. TreflectY = np.array([[-1, 0, 0], [0, 1, 0], [0, 0, 1]])
  86. trans2 = np.dot(trans2r, TreflectY)
  87. # Figure out if trans1 or trans2 is better
  88. xy1 = tformfwd(trans1, uv)
  89. norm1 = norm(xy1 - xy)
  90. xy2 = tformfwd(trans2, uv)
  91. norm2 = norm(xy2 - xy)
  92. if norm1 <= norm2:
  93. return trans1, trans1_inv
  94. else:
  95. trans2_inv = inv(trans2)
  96. return trans2, trans2_inv
  97. def get_similarity_transform(src_pts, dst_pts, reflective=True):
  98. """
  99. Function:
  100. ----------
  101. Find Similarity Transform Matrix 'trans':
  102. u = src_pts[:, 0]
  103. v = src_pts[:, 1]
  104. x = dst_pts[:, 0]
  105. y = dst_pts[:, 1]
  106. [x, y, 1] = [u, v, 1] * trans
  107. Parameters:
  108. ----------
  109. @src_pts: Kx2 np.array
  110. source points, each row is a pair of coordinates (x, y)
  111. @dst_pts: Kx2 np.array
  112. destination points, each row is a pair of transformed
  113. coordinates (x, y)
  114. @reflective: True or False
  115. if True:
  116. use reflective similarity transform
  117. else:
  118. use non-reflective similarity transform
  119. Returns:
  120. ----------
  121. @trans: 3x3 np.array
  122. transform matrix from uv to xy
  123. trans_inv: 3x3 np.array
  124. inverse of trans, transform matrix from xy to uv
  125. """
  126. if reflective:
  127. trans, trans_inv = findSimilarity(src_pts, dst_pts)
  128. else:
  129. trans, trans_inv = findNonreflectiveSimilarity(src_pts, dst_pts)
  130. return trans, trans_inv
  131. def cvt_tform_mat_for_cv2(trans):
  132. """
  133. Function:
  134. ----------
  135. Convert Transform Matrix 'trans' into 'cv2_trans' which could be
  136. directly used by cv2.warpAffine():
  137. u = src_pts[:, 0]
  138. v = src_pts[:, 1]
  139. x = dst_pts[:, 0]
  140. y = dst_pts[:, 1]
  141. [x, y].T = cv_trans * [u, v, 1].T
  142. Parameters:
  143. ----------
  144. @trans: 3x3 np.array
  145. transform matrix from uv to xy
  146. Returns:
  147. ----------
  148. @cv2_trans: 2x3 np.array
  149. transform matrix from src_pts to dst_pts, could be directly used
  150. for cv2.warpAffine()
  151. """
  152. cv2_trans = trans[:, 0:2].T
  153. return cv2_trans
  154. def get_similarity_transform_for_cv2(src_pts, dst_pts, reflective=True):
  155. """
  156. Function:
  157. ----------
  158. Find Similarity Transform Matrix 'cv2_trans' which could be
  159. directly used by cv2.warpAffine():
  160. u = src_pts[:, 0]
  161. v = src_pts[:, 1]
  162. x = dst_pts[:, 0]
  163. y = dst_pts[:, 1]
  164. [x, y].T = cv_trans * [u, v, 1].T
  165. Parameters:
  166. ----------
  167. @src_pts: Kx2 np.array
  168. source points, each row is a pair of coordinates (x, y)
  169. @dst_pts: Kx2 np.array
  170. destination points, each row is a pair of transformed
  171. coordinates (x, y)
  172. reflective: True or False
  173. if True:
  174. use reflective similarity transform
  175. else:
  176. use non-reflective similarity transform
  177. Returns:
  178. ----------
  179. @cv2_trans: 2x3 np.array
  180. transform matrix from src_pts to dst_pts, could be directly used
  181. for cv2.warpAffine()
  182. """
  183. trans, trans_inv = get_similarity_transform(src_pts, dst_pts, reflective)
  184. cv2_trans = cvt_tform_mat_for_cv2(trans)
  185. return cv2_trans
  186. if __name__ == "__main__":
  187. """
  188. u = [0, 6, -2]
  189. v = [0, 3, 5]
  190. x = [-1, 0, 4]
  191. y = [-1, -10, 4]
  192. # In Matlab, run:
  193. #
  194. # uv = [u'; v'];
  195. # xy = [x'; y'];
  196. # tform_sim=cp2tform(uv,xy,'similarity');
  197. #
  198. # trans = tform_sim.tdata.T
  199. # ans =
  200. # -0.0764 -1.6190 0
  201. # 1.6190 -0.0764 0
  202. # -3.2156 0.0290 1.0000
  203. # trans_inv = tform_sim.tdata.Tinv
  204. # ans =
  205. #
  206. # -0.0291 0.6163 0
  207. # -0.6163 -0.0291 0
  208. # -0.0756 1.9826 1.0000
  209. # xy_m=tformfwd(tform_sim, u,v)
  210. #
  211. # xy_m =
  212. #
  213. # -3.2156 0.0290
  214. # 1.1833 -9.9143
  215. # 5.0323 2.8853
  216. # uv_m=tforminv(tform_sim, x,y)
  217. #
  218. # uv_m =
  219. #
  220. # 0.5698 1.3953
  221. # 6.0872 2.2733
  222. # -2.6570 4.3314
  223. """
  224. u = [0, 6, -2]
  225. v = [0, 3, 5]
  226. x = [-1, 0, 4]
  227. y = [-1, -10, 4]
  228. uv = np.array((u, v)).T
  229. xy = np.array((x, y)).T
  230. print("\n--->uv:")
  231. print(uv)
  232. print("\n--->xy:")
  233. print(xy)
  234. trans, trans_inv = get_similarity_transform(uv, xy)
  235. print("\n--->trans matrix:")
  236. print(trans)
  237. print("\n--->trans_inv matrix:")
  238. print(trans_inv)
  239. print("\n---> apply transform to uv")
  240. print("\nxy_m = uv_augmented * trans")
  241. uv_aug = np.hstack((uv, np.ones((uv.shape[0], 1))))
  242. xy_m = np.dot(uv_aug, trans)
  243. print(xy_m)
  244. print("\nxy_m = tformfwd(trans, uv)")
  245. xy_m = tformfwd(trans, uv)
  246. print(xy_m)
  247. print("\n---> apply inverse transform to xy")
  248. print("\nuv_m = xy_augmented * trans_inv")
  249. xy_aug = np.hstack((xy, np.ones((xy.shape[0], 1))))
  250. uv_m = np.dot(xy_aug, trans_inv)
  251. print(uv_m)
  252. print("\nuv_m = tformfwd(trans_inv, xy)")
  253. uv_m = tformfwd(trans_inv, xy)
  254. print(uv_m)
  255. uv_m = tforminv(trans, xy)
  256. print("\nuv_m = tforminv(trans, xy)")
  257. print(uv_m)