+#include "DGtal/images/ImageSelector.h"
+#include "DGtal/images/GeometricTransformation2D.h"
+//////////////////////////////////////////////////////////////////////////////
+
+namespace DGtal
+{
+namespace functors
+{
+/////////////////////////////////////////////////////////////////////////////
+// Template class ForwardAffineTransformation2D
+/**
+ * Description of template functor like class 'ForwardAffineTransformation2D'
+ * \brief Aim: implements forward rigid transformation of point in the 2D integer space.
+ * Warring: This version uses closest neighbor interpolation.
+ *
+ * @tparam TSpace a 2 dimensional space.
+ * @tparam TInputValue type of the input point e.g., TSpace::RealPoint
+ * @tparam TOutputValue type of the output point e.g., TSpace::Point
+ * @tparam TFunctor a functor operating on the output e.g., a rounding function.
+ *
+ * @see exampleAffineTransformation3d.cpp
+ */
+template < typename TSpace, typename TInputValue = typename TSpace::RealPoint, typename TOutputValue = typename TSpace::Point,
+ typename TFunctor = VectorRounding < TInputValue, TOutputValue > >
+class ForwardAffineTransformation2D : public GeometricTransformation2D
+{
+ ///Checking concepts
+ BOOST_CONCEPT_ASSERT(( concepts::CSpace ));
+ BOOST_STATIC_ASSERT(( TSpace::dimension == 2 ));
+ BOOST_STATIC_ASSERT(( TOutputValue::dimension == 2 ));
+ BOOST_STATIC_ASSERT(( TInputValue::dimension == 2 ));
+
+ // ----------------------- Types ------------------------------
+public:
+ typedef typename TSpace::RealPoint RealPoint;
+ typedef typename TSpace::RealVector RealVector;
+ typedef Eigen::Matrix RealMatrix;
+
+ // ----------------------- Interface --------------------------------------
+public:
+ /**
+ * Constructor.
+ * @param aOrigin the center of affine transform.
+ * @param aMatrix the affine matrix.
+ * @param aTranslate the 2D dimensional vector which represents translation.
+ */
+ ForwardAffineTransformation2D ( const RealPoint & aOrigin, const RealMatrix & aMatrix, const RealVector & aTranslate )
+ {
+ this->origin = aOrigin;
+ BOOST_ASSERT((aMatrix(0,0)*aMatrix(1,1)!=aMatrix(1,0)*aMatrix(0,1)));
+ this->transform_matrix = aMatrix;
+ this->translation = aTranslate;
+ }
+
+ /**
+ * Constructor.
+ * @param a11, a12, a21, a22 the values of affine matrix.
+ * @param aTranslate the 2D dimensional vector which represents translation.
+ */
+ ForwardAffineTransformation2D ( const double a11, const double a12, const double a21, const double a22, const RealVector & aTranslate )
+ {
+ BOOST_ASSERT((a11*a22!=a12*a21));
+ this->origin = RealPoint(0,0);
+ RealMatrix aMatrix;
+ aMatrix(0,0) = a11;
+ aMatrix(0,1) = a12;
+ aMatrix(1,0) = a21;
+ aMatrix(1,1) = a22;
+ this->transform_matrix = aMatrix;
+ this->translation = aTranslate;
+ }
+}; //end of class ForwardAffineTransformation2D
+
+/////////////////////////////////////////////////////////////////////////////
+// Template class BackwardAffineTransformation2D
+/**
+ * Description of template functor like class 'BackwardAffineTransformation2D'
+ * \brief Aim: implements backward rigid transformation of point in the 2D integer space.
+ * Warring: This version uses closest neighbor interpolation.
+ *
+ * @tparam TSpace a 2 dimensional space.
+ * @tparam TInputValue type of the input point e.g., TSpace::RealPoint
+ * @tparam TOutputValue type of the output point e.g., TSpace::Point
+ * @tparam TFunctor a functor operating on the output e.g., a rounding function.
+ *
+ * @see exampleAffineTransformation3d.cpp
+ */
+template < typename TSpace, typename TInputValue = typename TSpace::RealPoint, typename TOutputValue = typename TSpace::Point,
+ typename TFunctor = VectorRounding < TInputValue, TOutputValue > >
+class BackwardAffineTransformation2D : public GeometricTransformation2D
+{
+ ///Checking concepts
+ BOOST_CONCEPT_ASSERT(( concepts::CSpace ));
+ BOOST_STATIC_ASSERT(( TSpace::dimension == 2 ));
+ BOOST_STATIC_ASSERT(( TOutputValue::dimension == 2 ));
+ //BOOST_STATIC_ASSERT(( TInputValue::dimension == 2 ));
+
+ // ----------------------- Types ------------------------------
+public:
+ typedef typename TSpace::RealPoint RealPoint;
+ typedef typename TSpace::RealVector RealVector;
+ typedef Eigen::Matrix RealMatrix;
+
+ // ----------------------- Interface --------------------------------------
+public:
+ /**
+ * Constructor.
+ * @param aOrigin the center of affine transform.
+ * @param aMatrix the affine matrix.
+ * @param aTranslate the 2D dimensional vector which represents translation.
+ */
+ BackwardAffineTransformation2D ( const RealPoint& aOrigin, const RealMatrix & aMatrix, const RealVector & aTranslate )
+ {
+ this->origin = aOrigin;
+ BOOST_ASSERT((aMatrix(0,0)*aMatrix(1,1)!=aMatrix(1,0)*aMatrix(0,1)));
+ this->transform_matrix = aMatrix;
+ this->translation = aTranslate;
+ }
+
+ /**
+ * Constructor.
+ * @param a11, a12, a21, a22 the values of affine matrix.
+ * @param aTranslate the 2D dimensional vector which represents translation.
+ */
+ BackwardAffineTransformation2D ( const double a11, const double a12, const double a21, const double a22, const RealVector & aTranslate )
+ {
+ BOOST_ASSERT((a11*a22!=a12*a21));
+ this->origin = RealPoint(0,0);
+ RealMatrix aMatrix;
+ double det = a11*a22-a21*a12;
+ aMatrix(0,0) = a22/det;
+ aMatrix(0,1) = -a12/det;
+ aMatrix(1,0) = -a21/det;
+ aMatrix(1,1) = a11/det;
+ this->transform_matrix = aMatrix;
+ this->translation = aTranslate;
+ }
+
+ TOutputValue operator()( const TInputValue & aInput ) const override
+ {
+ RealPoint p;
+ double a = this->transform_matrix(0,0);//transform_matrix.at(0).at(0);
+ double b = this->transform_matrix(0,1);//transform_matrix.at(0).at(1);
+ double c = this->transform_matrix(1,0);//transform_matrix.at(1).at(0);
+ double d = this->transform_matrix(1,1);//transform_matrix.at(1).at(1);
+ p[0] = ( a * ( aInput[0] - this->origin[0] - this->translation[0] ) +
+ b * ( aInput[1] - this->origin[1] - this->translation[1] ) ) + this->origin[0];
+
+ p[1] = ( c * ( aInput[0] - this->origin[0] - this->translation[0] ) +
+ d * ( aInput[1] - this->origin[1] - this->translation[1] ) ) + this->origin[1];
+ return this->functor ( p );
+ }
+};
+
+}// namespace DGtal::functors
+}// namespace DGtal
+
+#endif // !defined AffineTransformation2D_h
+
+#undef AffineTransformation2D_RECURSES
+#endif // else defined(AffineTransformation2D_RECURSES)
+
diff --git a/src/DGtal/images/GeometricTransformation2D.h b/src/DGtal/images/GeometricTransformation2D.h
new file mode 100755
index 0000000000..41633a95ef
--- /dev/null
+++ b/src/DGtal/images/GeometricTransformation2D.h
@@ -0,0 +1,214 @@
+/**
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ **/
+
+#pragma once
+
+/**
+ * @file GeometricTransformation2D.h
+ * @author Phuc Ngo (\c hoai-diem-phuc.ngo@loria.fr )
+ * Laboratoire Lorrain de Recherche en Informatique et ses Applications (LORIA), France
+ *
+ * @date 08/01/2021
+ *
+ * This file is part of the DGtal library.
+ */
+
+#if defined(GeometricTransformation2D_RECURSES)
+#error Recursive header files inclusion detected in GeometricTransformation2D.h
+#else // defined(GeometricTransformation2D_RECURSES)
+/** Prevents recursive inclusion of headers. */
+#define GeometricTransformation2D_RECURSES
+
+#if !defined GeometricTransformation2D_h
+/** Prevents repeated inclusion of headers. */
+#define GeometricTransformation2D_h
+
+//////////////////////////////////////////////////////////////////////////////
+// Inclusions
+#include
+#include
+#include
+#include
+#include "DGtal/base/Common.h"
+#include "DGtal/kernel/BasicPointFunctors.h"
+#include
+#include
+#include
+#include
+//////////////////////////////////////////////////////////////////////////////
+
+namespace DGtal
+{
+namespace functors
+{
+/////////////////////////////////////////////////////////////////////////////
+// Template class GeometricTransformation2D
+/**
+ * Description of template functor like class 'GeometricTransformation2D'
+ * \brief Aim: implements geometric transformation of point in the 2D integer space.
+ * This version uses closest neighbor interpolation.
+ *
+ * @tparam TSpace a 2 dimensional space.
+ * @tparam TInputValue type of the input point e.g., TSpace::RealPoint
+ * @tparam TOutputValue type of the output point e.g., TSpace::Point
+ * @tparam TFunctor a functor operating on the output e.g., a rounding function.
+ *
+ * @see exampleAffinetransformation2d.cpp
+ */
+template < typename TSpace, typename TInputValue = typename TSpace::RealPoint, typename TOutputValue = typename TSpace::Point,
+ typename TFunctor = VectorRounding < TInputValue, TOutputValue > >
+class GeometricTransformation2D
+{
+ ///Checking concepts
+ BOOST_CONCEPT_ASSERT(( concepts::CSpace ));
+ BOOST_STATIC_ASSERT(( TSpace::dimension == 2 ));
+ BOOST_STATIC_ASSERT(( TOutputValue::dimension == 2 ));
+ BOOST_STATIC_ASSERT(( TInputValue::dimension == 2 ));
+
+ // ----------------------- Types ------------------------------
+public:
+ typedef typename TSpace::RealPoint RealPoint;
+ typedef typename TSpace::RealVector RealVector;
+ typedef Eigen::Matrix RealMatrix;
+ // ------------------------- Protected Datas ------------------------------
+ protected:
+ TInputValue origin; //origin of transformation
+ RealMatrix transform_matrix; //Transformation matrix
+ RealVector translation; //Transmation vector
+ TFunctor functor; //Interpolation function
+ // ----------------------- Interface --------------------------------------
+public:
+
+ /**
+ * Defaut Constructor without parameter
+ */
+ GeometricTransformation2D () { }
+ /**
+ * Constructor.
+ * @param aOrigin the center of rotation.
+ * @param aMatrix the transformation matrix.
+ * @param aTranslate the 2D dimensional vector which represents translation.
+ */
+ GeometricTransformation2D ( const RealPoint & aOrigin, const RealMatrix & aMatrix, const RealVector & aTranslate )
+ : origin(aOrigin), translation(aTranslate) {
+ transform_matrix(0,0)=aMatrix(0,0);
+ transform_matrix(0,1)=aMatrix(0,1);
+ transform_matrix(1,0)=aMatrix(1,0);
+ transform_matrix(1,1)=aMatrix(1,1);
+ //std::cout << "transform_matrix:\n" << transform_matrix << std::endl;
+ }
+
+ /**
+ * Operator
+ *
+ * @return the transformed point.
+ */
+ inline
+ virtual
+ TOutputValue operator()( const TInputValue & aInput ) const
+ {
+ RealPoint p;
+ double a = transform_matrix(0,0);//transform_matrix.at(0).at(0);
+ double b = transform_matrix(0,1);//transform_matrix.at(0).at(1);
+ double c = transform_matrix(1,0);//transform_matrix.at(1).at(0);
+ double d = transform_matrix(1,1);//transform_matrix.at(1).at(1);
+ p[0] = ( ( a * ( aInput[0] - origin[0] ) +
+ b * ( aInput[1] - origin[1] ) ) + translation[0] ) + origin[0];
+
+ p[1] = ( ( c * ( aInput[0] - origin[0] ) +
+ d * ( aInput[1] - origin[1] ) ) + translation[1] ) + origin[1];
+ return functor ( p );
+ }
+
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// Template class DomainGeometricTransformation2D
+/**
+ * Description of template functor like class 'DomainGeometricTransformation2D'
+ * \brief Aim: implements bounds of transformed domain.
+ *
+ * @tparam TDomain a 2 dimensional domain.
+ * @tparam TGeometricTransformFunctor a functor which represent two dimensional geometric transformation.
+ *
+ * @see FIXME: exampleRigidtransformation2d.cpp
+ */
+template
+class DomainGeometricTransformation2D
+{
+ ///Checking concepts
+ BOOST_STATIC_ASSERT(( TDomain::dimension == 2 ));
+ BOOST_CONCEPT_ASSERT(( concepts::CDomain ));
+
+ // ----------------------- Types ------------------------------
+public:
+ typedef std::pair < typename TDomain::Space::Point, typename TDomain::Space::Point > Bounds;
+ // ------------------------- Protected Datas ------------------------------
+protected:
+ const TGeometricTransformFunctor & transform;
+ // ----------------------- Interface --------------------------------------
+public:
+ /**
+ * Constructor.
+ * @param aFunctor - geometric transformation functor.
+ */
+ DomainGeometricTransformation2D ( const TGeometricTransformFunctor & aFunctor ) : transform ( aFunctor ) {}
+
+ /**
+ * Operator
+ *
+ * @return bounds of the transformed domain.
+ */
+ inline
+ Bounds operator()( const TDomain & aInput ) const
+ {
+ typedef typename TDomain::Point Point;
+ Point points[4];
+ points[0] = transform ( aInput.lowerBound() );
+ points[1] = transform ( aInput.upperBound() );
+ points[2] = transform ( Point ( aInput.upperBound()[0], aInput.lowerBound()[1] ) );
+ points[3] = transform ( Point ( aInput.lowerBound()[0], aInput.upperBound()[1] ) );
+
+ Point t_min ( INT_MAX, INT_MAX ), t_max ( INT_MIN, INT_MIN );
+ for ( unsigned int i = 0; i < 4 ; i++ )
+ {
+ if ( points[i][0] < t_min[0] )
+ t_min[0] = points[i][0];
+ if ( points[i][1] < t_min[1] )
+ t_min[1] = points[i][1];
+
+ if ( points[i][0] > t_max[0] )
+ t_max[0] = points[i][0];
+ if ( points[i][1] > t_max[1] )
+ t_max[1] = points[i][1];
+ }
+
+ Bounds bounds;
+ bounds.first = t_min;
+ bounds.second = t_max;
+ return bounds;
+ }
+};
+
+}// namespace DGtal::functors
+}// namespace DGtal
+
+#endif // !defined GeometricTransformation2D_h
+
+#undef GeometricTransformation2D_RECURSES
+#endif // else defined(GeometricTransformation2D_RECURSES)
+
+
diff --git a/src/DGtal/images/doc/images/church_AffineBackward.png b/src/DGtal/images/doc/images/church_AffineBackward.png
new file mode 100644
index 0000000000..e57401f621
Binary files /dev/null and b/src/DGtal/images/doc/images/church_AffineBackward.png differ
diff --git a/src/DGtal/images/doc/images/church_AffineForward.png b/src/DGtal/images/doc/images/church_AffineForward.png
new file mode 100644
index 0000000000..72f055e91c
Binary files /dev/null and b/src/DGtal/images/doc/images/church_AffineForward.png differ
diff --git a/src/DGtal/images/doc/moduleGeometricalTransformation.dox b/src/DGtal/images/doc/moduleGeometricalTransformation.dox
index a65746de32..b036645bee 100644
--- a/src/DGtal/images/doc/moduleGeometricalTransformation.dox
+++ b/src/DGtal/images/doc/moduleGeometricalTransformation.dox
@@ -18,7 +18,7 @@ namespace DGtal {
//----------------------------------------
/*!
@page moduleGeometricTransform Geometric transformations
-@writers Kacper Pluta
+@writers Kacper Pluta, Phuc Ngo
@date 2014/07/17
[TOC]
@@ -147,7 +147,80 @@ and for backward as well:
\image html cat10_backward.jpg
\image latex cat10_backward.jpg
+
+\section secAffine2D Affine transformations
+
+Affine transformations in \f$\mathbb{R}^n\f$ is a geometric transformation which
+preserves collinearity and parallelism. Thus, rigid transformations are also affine transformations.
+
+In general an affine transformation can be written like:
+
+\f[
+\begin{array}{l l}
+ \mathcal{A}: \mathbb{R}^n & \to \mathbb{R}^n \\
+ \mathbf{x} & \mapsto \mathbf{A . x} + \mathbf{t}
+\end{array}
+\f]
+
+where \f$\textbf{A}\f$ denotes an invertible matrix and \f$\textbf{t}\f$
+translation vector. Then, discrete affine transformations can be
+defined as follows:
+
+\f[
+ A = \mathcal{D} \circ \mathcal{A}_{| \mathbb{Z}^n}
+\f]
+
+where \f$\mathcal{D}\f$ is a standard rounding function.
+
+\subsection subsecAffine2D Affine transformations in 2D discrete space
+In 2D, \f$\textbf{A}\f$ is a \f$2\times2\f$ matrix:
+
+\f[
+\mathbf{A} (a11,a12,a21,a22) =
+\begin{pmatrix}
+a11 & a12\\
+a21 & a22
+\end{pmatrix}
+\f]
+
+As rigid transformations, DGtal contains two models of discrete affine transformations: forward and backward.
+To use them, we need to:
+
+a) add those includes:
+@snippet images/exampleAffinetransformation2d.cpp include
+
+b) define these types:
+@snippet images/exampleAffinetransformation2d.cpp def
+
+where DomainGeometricTransformation2D is a helper functor which returns
+lower and upper bounds of transformed domain.
+
+c1) create transformation by providing information about the matrix \f$\textbf{A}\f$, and translation:
+
+@snippet images/exampleAffinetransformation2d.cpp trans
+
+c2) or create transformation by providing the origin, matrix \f$\textbf{A}\f$, and translation (e.g. @ref src/DGtal/images/AffineTransformation2D.h)
+
+d) if needed create a transformed domain eg:
+@snippet images/exampleAffinetransformation2d.cpp init_domain_helper
+@snippet images/exampleAffinetransformation2d.cpp domain
+
+e1) apply rigid transformation to image with forward model:
+@snippet images/exampleAffinetransformation2d.cpp forward
+
+e2) or with backward which can be used with ConstImageAdapter or ImageAdapter:
+@snippet images/exampleAffinetransformation2d.cpp backward
+
+Below image presents result for froward model and image "Church.pgm"
+\image html church_AffineForward.png
+\image latex church_AffineForward.png
+
+and for backward as well:
+\image html church_AffineBackward.png
+\image latex church_AffineBackward.png
+
*/
+
}