dualquaternion.inl.hpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487
  1. // This file is part of OpenCV project.
  2. // It is subject to the license terms in the LICENSE file found in the top-level directory
  3. // of this distribution and at http://opencv.org/license.html.
  4. //
  5. //
  6. // License Agreement
  7. // For Open Source Computer Vision Library
  8. //
  9. // Copyright (C) 2020, Huawei Technologies Co., Ltd. All rights reserved.
  10. // Third party copyrights are property of their respective owners.
  11. //
  12. // Licensed under the Apache License, Version 2.0 (the "License");
  13. // you may not use this file except in compliance with the License.
  14. // You may obtain a copy of the License at
  15. //
  16. // http://www.apache.org/licenses/LICENSE-2.0
  17. //
  18. // Unless required by applicable law or agreed to in writing, software
  19. // distributed under the License is distributed on an "AS IS" BASIS,
  20. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  21. // See the License for the specific language governing permissions and
  22. // limitations under the License.
  23. //
  24. // Author: Liangqian Kong <kongliangqian@huawei.com>
  25. // Longbu Wang <wanglongbu@huawei.com>
  26. #ifndef OPENCV_CORE_DUALQUATERNION_INL_HPP
  27. #define OPENCV_CORE_DUALQUATERNION_INL_HPP
  28. #ifndef OPENCV_CORE_DUALQUATERNION_HPP
  29. #error This is not a standalone header. Include dualquaternion.hpp instead.
  30. #endif
  31. ///////////////////////////////////////////////////////////////////////////////////////
  32. //Implementation
  33. namespace cv {
  34. template <typename T>
  35. DualQuat<T>::DualQuat():w(0), x(0), y(0), z(0), w_(0), x_(0), y_(0), z_(0){}
  36. template <typename T>
  37. DualQuat<T>::DualQuat(const T vw, const T vx, const T vy, const T vz, const T _w, const T _x, const T _y, const T _z):
  38. w(vw), x(vx), y(vy), z(vz), w_(_w), x_(_x), y_(_y), z_(_z){}
  39. template <typename T>
  40. DualQuat<T>::DualQuat(const Vec<T, 8> &q):w(q[0]), x(q[1]), y(q[2]), z(q[3]),
  41. w_(q[4]), x_(q[5]), y_(q[6]), z_(q[7]){}
  42. template <typename T>
  43. DualQuat<T> DualQuat<T>::createFromQuat(const Quat<T> &realPart, const Quat<T> &dualPart)
  44. {
  45. T w = realPart.w;
  46. T x = realPart.x;
  47. T y = realPart.y;
  48. T z = realPart.z;
  49. T w_ = dualPart.w;
  50. T x_ = dualPart.x;
  51. T y_ = dualPart.y;
  52. T z_ = dualPart.z;
  53. return DualQuat<T>(w, x, y, z, w_, x_, y_, z_);
  54. }
  55. template <typename T>
  56. DualQuat<T> DualQuat<T>::createFromAngleAxisTrans(const T angle, const Vec<T, 3> &axis, const Vec<T, 3> &trans)
  57. {
  58. Quat<T> r = Quat<T>::createFromAngleAxis(angle, axis);
  59. Quat<T> t{0, trans[0], trans[1], trans[2]};
  60. return createFromQuat(r, t * r * T(0.5));
  61. }
  62. template <typename T>
  63. DualQuat<T> DualQuat<T>::createFromMat(InputArray _R)
  64. {
  65. CV_CheckTypeEQ(_R.type(), cv::traits::Type<T>::value, "");
  66. if (_R.size() != Size(4, 4))
  67. {
  68. CV_Error(Error::StsBadArg, "The input matrix must have 4 columns and 4 rows");
  69. }
  70. Mat R = _R.getMat();
  71. Quat<T> r = Quat<T>::createFromRotMat(R.colRange(0, 3).rowRange(0, 3));
  72. Quat<T> trans(0, R.at<T>(0, 3), R.at<T>(1, 3), R.at<T>(2, 3));
  73. return createFromQuat(r, trans * r * T(0.5));
  74. }
  75. template <typename T>
  76. DualQuat<T> DualQuat<T>::createFromAffine3(const Affine3<T> &R)
  77. {
  78. return createFromMat(R.matrix);
  79. }
  80. template <typename T>
  81. DualQuat<T> DualQuat<T>::createFromPitch(const T angle, const T d, const Vec<T, 3> &axis, const Vec<T, 3> &moment)
  82. {
  83. T half_angle = angle * T(0.5), half_d = d * T(0.5);
  84. Quat<T> qaxis = Quat<T>(0, axis[0], axis[1], axis[2]).normalize();
  85. Quat<T> qmoment = Quat<T>(0, moment[0], moment[1], moment[2]);
  86. qmoment -= qaxis * axis.dot(moment);
  87. Quat<T> dual = -half_d * std::sin(half_angle) + std::sin(half_angle) * qmoment +
  88. half_d * std::cos(half_angle) * qaxis;
  89. return createFromQuat(Quat<T>::createFromAngleAxis(angle, axis), dual);
  90. }
  91. template <typename T>
  92. inline bool DualQuat<T>::operator==(const DualQuat<T> &q) const
  93. {
  94. return (abs(w - q.w) < CV_DUAL_QUAT_EPS && abs(x - q.x) < CV_DUAL_QUAT_EPS &&
  95. abs(y - q.y) < CV_DUAL_QUAT_EPS && abs(z - q.z) < CV_DUAL_QUAT_EPS &&
  96. abs(w_ - q.w_) < CV_DUAL_QUAT_EPS && abs(x_ - q.x_) < CV_DUAL_QUAT_EPS &&
  97. abs(y_ - q.y_) < CV_DUAL_QUAT_EPS && abs(z_ - q.z_) < CV_DUAL_QUAT_EPS);
  98. }
  99. template <typename T>
  100. inline Quat<T> DualQuat<T>::getRealPart() const
  101. {
  102. return Quat<T>(w, x, y, z);
  103. }
  104. template <typename T>
  105. inline Quat<T> DualQuat<T>::getDualPart() const
  106. {
  107. return Quat<T>(w_, x_, y_, z_);
  108. }
  109. template <typename T>
  110. inline DualQuat<T> conjugate(const DualQuat<T> &dq)
  111. {
  112. return dq.conjugate();
  113. }
  114. template <typename T>
  115. inline DualQuat<T> DualQuat<T>::conjugate() const
  116. {
  117. return DualQuat<T>(w, -x, -y, -z, w_, -x_, -y_, -z_);
  118. }
  119. template <typename T>
  120. DualQuat<T> DualQuat<T>::norm() const
  121. {
  122. Quat<T> real = getRealPart();
  123. T realNorm = real.norm();
  124. Quat<T> dual = getDualPart();
  125. if (realNorm < CV_DUAL_QUAT_EPS){
  126. return DualQuat<T>(0, 0, 0, 0, 0, 0, 0, 0);
  127. }
  128. return DualQuat<T>(realNorm, 0, 0, 0, real.dot(dual) / realNorm, 0, 0, 0);
  129. }
  130. template <typename T>
  131. inline Quat<T> DualQuat<T>::getRotation(QuatAssumeType assumeUnit) const
  132. {
  133. if (assumeUnit)
  134. {
  135. return getRealPart();
  136. }
  137. return getRealPart().normalize();
  138. }
  139. template <typename T>
  140. inline Vec<T, 3> DualQuat<T>::getTranslation(QuatAssumeType assumeUnit) const
  141. {
  142. Quat<T> trans = T(2.0) * (getDualPart() * getRealPart().inv(assumeUnit));
  143. return Vec<T, 3>{trans[1], trans[2], trans[3]};
  144. }
  145. template <typename T>
  146. DualQuat<T> DualQuat<T>::normalize() const
  147. {
  148. Quat<T> p = getRealPart();
  149. Quat<T> q = getDualPart();
  150. T p_norm = p.norm();
  151. if (p_norm < CV_DUAL_QUAT_EPS)
  152. {
  153. CV_Error(Error::StsBadArg, "Cannot normalize this dual quaternion: the norm is too small.");
  154. }
  155. Quat<T> p_nr = p / p_norm;
  156. Quat<T> q_nr = q / p_norm;
  157. return createFromQuat(p_nr, q_nr - p_nr * p_nr.dot(q_nr));
  158. }
  159. template <typename T>
  160. inline T DualQuat<T>::dot(DualQuat<T> q) const
  161. {
  162. return q.w * w + q.x * x + q.y * y + q.z * z + q.w_ * w_ + q.x_ * x_ + q.y_ * y_ + q.z_ * z_;
  163. }
  164. template <typename T>
  165. inline DualQuat<T> inv(const DualQuat<T> &dq, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT)
  166. {
  167. return dq.inv(assumeUnit);
  168. }
  169. template <typename T>
  170. inline DualQuat<T> DualQuat<T>::inv(QuatAssumeType assumeUnit) const
  171. {
  172. Quat<T> real = getRealPart();
  173. Quat<T> dual = getDualPart();
  174. return createFromQuat(real.inv(assumeUnit), -real.inv(assumeUnit) * dual * real.inv(assumeUnit));
  175. }
  176. template <typename T>
  177. inline DualQuat<T> DualQuat<T>::operator-(const DualQuat<T> &q) const
  178. {
  179. return DualQuat<T>(w - q.w, x - q.x, y - q.y, z - q.z, w_ - q.w_, x_ - q.x_, y_ - q.y_, z_ - q.z_);
  180. }
  181. template <typename T>
  182. inline DualQuat<T> DualQuat<T>::operator-() const
  183. {
  184. return DualQuat<T>(-w, -x, -y, -z, -w_, -x_, -y_, -z_);
  185. }
  186. template <typename T>
  187. inline DualQuat<T> DualQuat<T>::operator+(const DualQuat<T> &q) const
  188. {
  189. return DualQuat<T>(w + q.w, x + q.x, y + q.y, z + q.z, w_ + q.w_, x_ + q.x_, y_ + q.y_, z_ + q.z_);
  190. }
  191. template <typename T>
  192. inline DualQuat<T>& DualQuat<T>::operator+=(const DualQuat<T> &q)
  193. {
  194. *this = *this + q;
  195. return *this;
  196. }
  197. template <typename T>
  198. inline DualQuat<T> DualQuat<T>::operator*(const DualQuat<T> &q) const
  199. {
  200. Quat<T> A = getRealPart();
  201. Quat<T> B = getDualPart();
  202. Quat<T> C = q.getRealPart();
  203. Quat<T> D = q.getDualPart();
  204. return DualQuat<T>::createFromQuat(A * C, A * D + B * C);
  205. }
  206. template <typename T>
  207. inline DualQuat<T>& DualQuat<T>::operator*=(const DualQuat<T> &q)
  208. {
  209. *this = *this * q;
  210. return *this;
  211. }
  212. template <typename T>
  213. inline DualQuat<T> operator+(const T a, const DualQuat<T> &q)
  214. {
  215. return DualQuat<T>(a + q.w, q.x, q.y, q.z, q.w_, q.x_, q.y_, q.z_);
  216. }
  217. template <typename T>
  218. inline DualQuat<T> operator+(const DualQuat<T> &q, const T a)
  219. {
  220. return DualQuat<T>(a + q.w, q.x, q.y, q.z, q.w_, q.x_, q.y_, q.z_);
  221. }
  222. template <typename T>
  223. inline DualQuat<T> operator-(const DualQuat<T> &q, const T a)
  224. {
  225. return DualQuat<T>(q.w - a, q.x, q.y, q.z, q.w_, q.x_, q.y_, q.z_);
  226. }
  227. template <typename T>
  228. inline DualQuat<T>& DualQuat<T>::operator-=(const DualQuat<T> &q)
  229. {
  230. *this = *this - q;
  231. return *this;
  232. }
  233. template <typename T>
  234. inline DualQuat<T> operator-(const T a, const DualQuat<T> &q)
  235. {
  236. return DualQuat<T>(a - q.w, -q.x, -q.y, -q.z, -q.w_, -q.x_, -q.y_, -q.z_);
  237. }
  238. template <typename T>
  239. inline DualQuat<T> operator*(const T a, const DualQuat<T> &q)
  240. {
  241. return DualQuat<T>(q.w * a, q.x * a, q.y * a, q.z * a, q.w_ * a, q.x_ * a, q.y_ * a, q.z_ * a);
  242. }
  243. template <typename T>
  244. inline DualQuat<T> operator*(const DualQuat<T> &q, const T a)
  245. {
  246. return DualQuat<T>(q.w * a, q.x * a, q.y * a, q.z * a, q.w_ * a, q.x_ * a, q.y_ * a, q.z_ * a);
  247. }
  248. template <typename T>
  249. inline DualQuat<T> DualQuat<T>::operator/(const T a) const
  250. {
  251. return DualQuat<T>(w / a, x / a, y / a, z / a, w_ / a, x_ / a, y_ / a, z_ / a);
  252. }
  253. template <typename T>
  254. inline DualQuat<T> DualQuat<T>::operator/(const DualQuat<T> &q) const
  255. {
  256. return *this * q.inv();
  257. }
  258. template <typename T>
  259. inline DualQuat<T>& DualQuat<T>::operator/=(const DualQuat<T> &q)
  260. {
  261. *this = *this / q;
  262. return *this;
  263. }
  264. template <typename T>
  265. std::ostream & operator<<(std::ostream &os, const DualQuat<T> &q)
  266. {
  267. os << "DualQuat " << Vec<T, 8>{q.w, q.x, q.y, q.z, q.w_, q.x_, q.y_, q.z_};
  268. return os;
  269. }
  270. template <typename T>
  271. inline DualQuat<T> exp(const DualQuat<T> &dq)
  272. {
  273. return dq.exp();
  274. }
  275. namespace detail {
  276. template <typename _Tp>
  277. Matx<_Tp, 4, 4> jacob_exp(const Quat<_Tp> &q)
  278. {
  279. _Tp nv = std::sqrt(q.x * q.x + q.y * q.y + q.z * q.z);
  280. _Tp sinc_nv = abs(nv) < cv::DualQuat<_Tp>::CV_DUAL_QUAT_EPS ? _Tp(1.0) - nv * nv * _Tp(1.0/6.0) : std::sin(nv) / nv;
  281. _Tp csiii_nv = abs(nv) < cv::DualQuat<_Tp>::CV_DUAL_QUAT_EPS ? -_Tp(1.0/3.0) : (std::cos(nv) - sinc_nv) / nv / nv;
  282. Matx<_Tp, 4, 4> J_exp_quat {
  283. std::cos(nv), -sinc_nv * q.x, -sinc_nv * q.y, -sinc_nv * q.z,
  284. sinc_nv * q.x, csiii_nv * q.x * q.x + sinc_nv, csiii_nv * q.x * q.y, csiii_nv * q.x * q.z,
  285. sinc_nv * q.y, csiii_nv * q.y * q.x, csiii_nv * q.y * q.y + sinc_nv, csiii_nv * q.y * q.z,
  286. sinc_nv * q.z, csiii_nv * q.z * q.x, csiii_nv * q.z * q.y, csiii_nv * q.z * q.z + sinc_nv
  287. };
  288. return std::exp(q.w) * J_exp_quat;
  289. }
  290. } // namespace detail
  291. template <typename T>
  292. DualQuat<T> DualQuat<T>::exp() const
  293. {
  294. Quat<T> real = getRealPart();
  295. return createFromQuat(real.exp(), Quat<T>(detail::jacob_exp(real) * getDualPart().toVec()));
  296. }
  297. template <typename T>
  298. DualQuat<T> log(const DualQuat<T> &dq, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT)
  299. {
  300. return dq.log(assumeUnit);
  301. }
  302. template <typename T>
  303. DualQuat<T> DualQuat<T>::log(QuatAssumeType assumeUnit) const
  304. {
  305. Quat<T> plog = getRealPart().log(assumeUnit);
  306. Matx<T, 4, 4> jacob = detail::jacob_exp(plog);
  307. return createFromQuat(plog, Quat<T>(jacob.inv() * getDualPart().toVec()));
  308. }
  309. template <typename T>
  310. inline DualQuat<T> power(const DualQuat<T> &dq, const T t, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT)
  311. {
  312. return dq.power(t, assumeUnit);
  313. }
  314. template <typename T>
  315. inline DualQuat<T> DualQuat<T>::power(const T t, QuatAssumeType assumeUnit) const
  316. {
  317. return (t * log(assumeUnit)).exp();
  318. }
  319. template <typename T>
  320. inline DualQuat<T> power(const DualQuat<T> &p, const DualQuat<T> &q, QuatAssumeType assumeUnit=QUAT_ASSUME_NOT_UNIT)
  321. {
  322. return p.power(q, assumeUnit);
  323. }
  324. template <typename T>
  325. inline DualQuat<T> DualQuat<T>::power(const DualQuat<T> &q, QuatAssumeType assumeUnit) const
  326. {
  327. return (q * log(assumeUnit)).exp();
  328. }
  329. template <typename T>
  330. inline Vec<T, 8> DualQuat<T>::toVec() const
  331. {
  332. return Vec<T, 8>(w, x, y, z, w_, x_, y_, z_);
  333. }
  334. template <typename T>
  335. Affine3<T> DualQuat<T>::toAffine3(QuatAssumeType assumeUnit) const
  336. {
  337. return Affine3<T>(toMat(assumeUnit));
  338. }
  339. template <typename T>
  340. Matx<T, 4, 4> DualQuat<T>::toMat(QuatAssumeType assumeUnit) const
  341. {
  342. Matx<T, 4, 4> rot44 = getRotation(assumeUnit).toRotMat4x4();
  343. Vec<T, 3> translation = getTranslation(assumeUnit);
  344. rot44(0, 3) = translation[0];
  345. rot44(1, 3) = translation[1];
  346. rot44(2, 3) = translation[2];
  347. return rot44;
  348. }
  349. template <typename T>
  350. DualQuat<T> DualQuat<T>::sclerp(const DualQuat<T> &q0, const DualQuat<T> &q1, const T t, bool directChange, QuatAssumeType assumeUnit)
  351. {
  352. DualQuat<T> v0(q0), v1(q1);
  353. if (!assumeUnit)
  354. {
  355. v0 = v0.normalize();
  356. v1 = v1.normalize();
  357. }
  358. Quat<T> v0Real = v0.getRealPart();
  359. Quat<T> v1Real = v1.getRealPart();
  360. if (directChange && v1Real.dot(v0Real) < 0)
  361. {
  362. v0 = -v0;
  363. }
  364. DualQuat<T> v0inv1 = v0.inv() * v1;
  365. return v0 * v0inv1.power(t, QUAT_ASSUME_UNIT);
  366. }
  367. template <typename T>
  368. DualQuat<T> DualQuat<T>::dqblend(const DualQuat<T> &q1, const DualQuat<T> &q2, const T t, QuatAssumeType assumeUnit)
  369. {
  370. DualQuat<T> v1(q1), v2(q2);
  371. if (!assumeUnit)
  372. {
  373. v1 = v1.normalize();
  374. v2 = v2.normalize();
  375. }
  376. if (v1.getRotation(assumeUnit).dot(v2.getRotation(assumeUnit)) < 0)
  377. {
  378. return ((1 - t) * v1 - t * v2).normalize();
  379. }
  380. return ((1 - t) * v1 + t * v2).normalize();
  381. }
  382. template <typename T>
  383. DualQuat<T> DualQuat<T>::gdqblend(InputArray _dualquat, InputArray _weight, QuatAssumeType assumeUnit)
  384. {
  385. CV_CheckTypeEQ(_weight.type(), cv::traits::Type<T>::value, "");
  386. CV_CheckTypeEQ(_dualquat.type(), CV_MAKETYPE(CV_MAT_DEPTH(cv::traits::Type<T>::value), 8), "");
  387. Size dq_s = _dualquat.size();
  388. if (dq_s != _weight.size() || (dq_s.height != 1 && dq_s.width != 1))
  389. {
  390. CV_Error(Error::StsBadArg, "The size of weight must be the same as dualquat, both of them should be (1, n) or (n, 1)");
  391. }
  392. Mat dualquat = _dualquat.getMat(), weight = _weight.getMat();
  393. const int cn = std::max(dq_s.width, dq_s.height);
  394. if (!assumeUnit)
  395. {
  396. for (int i = 0; i < cn; ++i)
  397. {
  398. dualquat.at<Vec<T, 8>>(i) = DualQuat<T>{dualquat.at<Vec<T, 8>>(i)}.normalize().toVec();
  399. }
  400. }
  401. Vec<T, 8> dq_blend = dualquat.at<Vec<T, 8>>(0) * weight.at<T>(0);
  402. Quat<T> q0 = DualQuat<T> {dualquat.at<Vec<T, 8>>(0)}.getRotation(assumeUnit);
  403. for (int i = 1; i < cn; ++i)
  404. {
  405. T k = q0.dot(DualQuat<T>{dualquat.at<Vec<T, 8>>(i)}.getRotation(assumeUnit)) < 0 ? -1: 1;
  406. dq_blend = dq_blend + dualquat.at<Vec<T, 8>>(i) * k * weight.at<T>(i);
  407. }
  408. return DualQuat<T>{dq_blend}.normalize();
  409. }
  410. template <typename T>
  411. template <int cn>
  412. DualQuat<T> DualQuat<T>::gdqblend(const Vec<DualQuat<T>, cn> &_dualquat, InputArray _weight, QuatAssumeType assumeUnit)
  413. {
  414. Vec<DualQuat<T>, cn> dualquat(_dualquat);
  415. if (cn == 0)
  416. {
  417. return DualQuat<T>(1, 0, 0, 0, 0, 0, 0, 0);
  418. }
  419. Mat dualquat_mat(cn, 1, CV_64FC(8));
  420. for (int i = 0; i < cn ; ++i)
  421. {
  422. dualquat_mat.at<Vec<T, 8>>(i) = dualquat[i].toVec();
  423. }
  424. return gdqblend(dualquat_mat, _weight, assumeUnit);
  425. }
  426. } //namespace cv
  427. #endif /*OPENCV_CORE_DUALQUATERNION_INL_HPP*/