affine.hpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. //
  2. // Copyright 2005-2007 Adobe Systems Incorporated
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. #ifndef BOOST_GIL_EXTENSION_NUMERIC_AFFINE_HPP
  9. #define BOOST_GIL_EXTENSION_NUMERIC_AFFINE_HPP
  10. #include <boost/gil/point.hpp>
  11. namespace boost { namespace gil {
  12. ////////////////////////////////////////////////////////////////////////////////////////
  13. ///
  14. /// Simple matrix to do 2D affine transformations. It is actually 3x3 but the last column is [0 0 1]
  15. ///
  16. ////////////////////////////////////////////////////////////////////////////////////////
  17. template <typename T>
  18. class matrix3x2 {
  19. public:
  20. matrix3x2() : a(1), b(0), c(0), d(1), e(0), f(0) {}
  21. matrix3x2(T A, T B, T C, T D, T E, T F) : a(A),b(B),c(C),d(D),e(E),f(F) {}
  22. matrix3x2(const matrix3x2& mat) : a(mat.a), b(mat.b), c(mat.c), d(mat.d), e(mat.e), f(mat.f) {}
  23. matrix3x2& operator=(const matrix3x2& m) { a=m.a; b=m.b; c=m.c; d=m.d; e=m.e; f=m.f; return *this; }
  24. matrix3x2& operator*=(const matrix3x2& m) { (*this) = (*this)*m; return *this; }
  25. static matrix3x2 get_rotate(T rads) { T c=std::cos(rads); T s=std::sin(rads); return matrix3x2(c,s,-s,c,0,0); }
  26. static matrix3x2 get_translate(point<T> const& t)
  27. {
  28. return matrix3x2(1, 0, 0, 1, t.x, t.y);
  29. }
  30. static matrix3x2 get_translate(T x, T y) { return matrix3x2(1 ,0,0,1 ,x, y ); }
  31. static matrix3x2 get_scale(point<T> const& s)
  32. {
  33. return matrix3x2(s.x, 0, 0, s.y, 0, 0);
  34. }
  35. static matrix3x2 get_scale(T x, T y) { return matrix3x2(x, 0,0,y, 0 ,0 ); }
  36. static matrix3x2 get_scale(T s) { return matrix3x2(s ,0,0,s ,0 ,0 ); }
  37. T a,b,c,d,e,f;
  38. };
  39. template <typename T> BOOST_FORCEINLINE
  40. matrix3x2<T> operator*(const matrix3x2<T>& m1, const matrix3x2<T>& m2) {
  41. return matrix3x2<T>(
  42. m1.a * m2.a + m1.b * m2.c,
  43. m1.a * m2.b + m1.b * m2.d,
  44. m1.c * m2.a + m1.d * m2.c,
  45. m1.c * m2.b + m1.d * m2.d,
  46. m1.e * m2.a + m1.f * m2.c + m2.e,
  47. m1.e * m2.b + m1.f * m2.d + m2.f );
  48. }
  49. template <typename T, typename F>
  50. BOOST_FORCEINLINE
  51. point<F> operator*(point<T> const& p, matrix3x2<F> const& m)
  52. {
  53. return { m.a*p.x + m.c*p.y + m.e, m.b*p.x + m.d*p.y + m.f };
  54. }
  55. ////////////////////////////////////////////////////////////////////////////////////////
  56. /// Define affine mapping that transforms the source coordinates by the affine transformation
  57. ////////////////////////////////////////////////////////////////////////////////////////
  58. /*
  59. template <typename MapFn>
  60. concept MappingFunctionConcept {
  61. typename mapping_traits<MapFn>::result_type; where PointNDConcept<result_type>;
  62. template <typename Domain> { where PointNDConcept<Domain> }
  63. result_type transform(MapFn&, const Domain& src);
  64. };
  65. */
  66. template <typename T> struct mapping_traits;
  67. template <typename F>
  68. struct mapping_traits<matrix3x2<F>>
  69. {
  70. using result_type = point<F>;
  71. };
  72. template <typename F, typename F2>
  73. BOOST_FORCEINLINE
  74. point<F> transform(matrix3x2<F> const& mat, point<F2> const& src)
  75. {
  76. return src * mat;
  77. }
  78. /// Returns the inverse of the given affine transformation matrix
  79. ///
  80. /// \warning Floating point arithmetic, use Boost.Rational if precision maters
  81. template <typename T>
  82. boost::gil::matrix3x2<T> inverse(boost::gil::matrix3x2<T> m)
  83. {
  84. T const determinant = m.a * m.d - m.b * m.c;
  85. boost::gil::matrix3x2<T> res;
  86. res.a = m.d / determinant;
  87. res.b = -m.b / determinant;
  88. res.c = -m.c / determinant;
  89. res.d = m.a / determinant;
  90. res.e = (m.c * m.f - m.d * m.e) / determinant;
  91. res.f = (m.b * m.e - m.a * m.f) / determinant;
  92. return res;
  93. }
  94. /// \fn gil::matrix3x2 center_rotate
  95. /// \tparam T Data type for source image dimensions
  96. /// \tparam F Data type for angle through which image is to be rotated
  97. /// @param dims dimensions of source image
  98. /// @param rads angle through which image is to be rotated
  99. /// @return A transformation matrix for rotating the source image about its center
  100. /// \brief rotates an image from its center point
  101. /// using consecutive affine transformations.
  102. template<typename T, typename F>
  103. boost::gil::matrix3x2<F> center_rotate(boost::gil::point<T> dims,F rads)
  104. {
  105. const F PI = F(3.141592653589793238);
  106. const F c_theta = std::abs(std::cos(rads));
  107. const F s_theta = std::abs(std::sin(rads));
  108. // Bound checks for angle rads
  109. while(rads + PI < 0)
  110. {
  111. rads = rads + PI;
  112. }
  113. while(rads > PI)
  114. {
  115. rads = rads - PI;
  116. }
  117. // Basic Rotation Matrix
  118. boost::gil::matrix3x2<F> rotate = boost::gil::matrix3x2<F>::get_rotate(rads);
  119. // Find distance for translating the image into view
  120. boost::gil::matrix3x2<F> translation(0,0,0,0,0,0);
  121. if(rads > 0)
  122. {
  123. translation.b = s_theta;
  124. }
  125. else
  126. {
  127. translation.c = s_theta;
  128. }
  129. if(std::abs(rads) > PI/2)
  130. {
  131. translation.a = c_theta;
  132. translation.d = c_theta;
  133. }
  134. // To bring the complete image into view
  135. boost::gil::matrix3x2<F> translate =
  136. boost::gil::matrix3x2<F>::get_translate(-1 * dims * translation);
  137. // To fit inside the source dimensions
  138. boost::gil::matrix3x2<F> scale =
  139. boost::gil::matrix3x2<F>::get_scale(
  140. s_theta * dims.y / dims.x + c_theta ,
  141. s_theta * dims.x / dims.y + c_theta
  142. );
  143. return scale * translate * rotate;
  144. }
  145. }} // namespace boost::gil
  146. #endif