Commit ee79c1f4 authored by Vadim Pisarevsky's avatar Vadim Pisarevsky

Merge pull request #988 from sovrasov:reg_python_bindings

parents d879ea48 17c45536
...@@ -121,13 +121,13 @@ namespace reg { ...@@ -121,13 +121,13 @@ namespace reg {
The class is only used to define the common interface for any possible map. The class is only used to define the common interface for any possible map.
*/ */
class CV_EXPORTS Map class CV_EXPORTS_W Map
{ {
public: public:
/*! /*!
* Virtual destructor * Virtual destructor
*/ */
virtual ~Map(void); virtual ~Map();
/*! /*!
* Warps image to a new coordinate frame. The calculation is img2(x)=img1(T^{-1}(x)), as we * Warps image to a new coordinate frame. The calculation is img2(x)=img1(T^{-1}(x)), as we
...@@ -136,7 +136,7 @@ public: ...@@ -136,7 +136,7 @@ public:
* \param[in] img1 Original image * \param[in] img1 Original image
* \param[out] img2 Warped image * \param[out] img2 Warped image
*/ */
virtual void warp(const cv::Mat& img1, cv::Mat& img2) const; CV_WRAP virtual void warp(InputArray img1, OutputArray img2) const;
/*! /*!
* Warps image to a new coordinate frame. The calculation is img2(x)=img1(T(x)), so in fact * Warps image to a new coordinate frame. The calculation is img2(x)=img1(T(x)), so in fact
...@@ -145,27 +145,27 @@ public: ...@@ -145,27 +145,27 @@ public:
* \param[in] img1 Original image * \param[in] img1 Original image
* \param[out] img2 Warped image * \param[out] img2 Warped image
*/ */
virtual void inverseWarp(const cv::Mat& img1, cv::Mat& img2) const = 0; CV_WRAP virtual void inverseWarp(InputArray img1, OutputArray img2) const = 0;
/*! /*!
* Calculates the inverse map * Calculates the inverse map
* \return Inverse map * \return Inverse map
*/ */
virtual cv::Ptr<Map> inverseMap(void) const = 0; CV_WRAP virtual cv::Ptr<Map> inverseMap() const = 0;
/*! /*!
* Changes the map composing the current transformation with the one provided in the call. * Changes the map composing the current transformation with the one provided in the call.
* The order is first the current transformation, then the input argument. * The order is first the current transformation, then the input argument.
* \param[in] map Transformation to compose with. * \param[in] map Transformation to compose with.
*/ */
virtual void compose(const Map& map) = 0; CV_WRAP virtual void compose(cv::Ptr<Map> map) = 0;
/*! /*!
* Scales the map by a given factor as if the coordinates system is expanded/compressed * Scales the map by a given factor as if the coordinates system is expanded/compressed
* by that factor. * by that factor.
* \param[in] factor Expansion if bigger than one, compression if smaller than one * \param[in] factor Expansion if bigger than one, compression if smaller than one
*/ */
virtual void scale(double factor) = 0; CV_WRAP virtual void scale(double factor) = 0;
}; };
//! @} //! @}
......
...@@ -49,13 +49,13 @@ namespace reg { ...@@ -49,13 +49,13 @@ namespace reg {
/*! /*!
* Defines an affine transformation * Defines an affine transformation
*/ */
class CV_EXPORTS MapAffine : public Map class CV_EXPORTS_W MapAffine : public Map
{ {
public: public:
/*! /*!
* Default constructor builds an identity map * Default constructor builds an identity map
*/ */
MapAffine(void); CV_WRAP MapAffine();
/*! /*!
* Constructor providing explicit values * Constructor providing explicit values
...@@ -67,15 +67,15 @@ public: ...@@ -67,15 +67,15 @@ public:
/*! /*!
* Destructor * Destructor
*/ */
~MapAffine(void); ~MapAffine();
void inverseWarp(const cv::Mat& img1, cv::Mat& img2) const; CV_WRAP void inverseWarp(InputArray img1, OutputArray img2) const;
cv::Ptr<Map> inverseMap(void) const; CV_WRAP cv::Ptr<Map> inverseMap() const;
void compose(const Map& map); CV_WRAP void compose(cv::Ptr<Map> map);
void scale(double factor); CV_WRAP void scale(double factor);
/*! /*!
* Return linear part of the affine transformation * Return linear part of the affine transformation
...@@ -85,6 +85,10 @@ public: ...@@ -85,6 +85,10 @@ public:
return linTr_; return linTr_;
} }
CV_WRAP void getLinTr(OutputArray linTr) const {
Mat(linTr_).copyTo(linTr);
}
/*! /*!
* Return displacement part of the affine transformation * Return displacement part of the affine transformation
* \return Displacement part of the affine transformation * \return Displacement part of the affine transformation
...@@ -93,6 +97,10 @@ public: ...@@ -93,6 +97,10 @@ public:
return shift_; return shift_;
} }
CV_WRAP void getShift(OutputArray shift) const {
Mat(shift_).copyTo(shift);
}
private: private:
cv::Matx<double, 2, 2> linTr_; cv::Matx<double, 2, 2> linTr_;
cv::Vec<double, 2> shift_; cv::Vec<double, 2> shift_;
......
...@@ -47,11 +47,11 @@ namespace reg { ...@@ -47,11 +47,11 @@ namespace reg {
//! @addtogroup reg //! @addtogroup reg
//! @{ //! @{
/** @brief Base class for modelling an algorithm for calculating a /** @brief Base class for modelling an algorithm for calculating a map
The class is only used to define the common interface for any possible mapping algorithm. The class is only used to define the common interface for any possible mapping algorithm.
*/ */
class CV_EXPORTS Mapper class CV_EXPORTS_W Mapper
{ {
public: public:
virtual ~Mapper(void) {} virtual ~Mapper(void) {}
...@@ -60,16 +60,16 @@ public: ...@@ -60,16 +60,16 @@ public:
* Calculate mapping between two images * Calculate mapping between two images
* \param[in] img1 Reference image * \param[in] img1 Reference image
* \param[in] img2 Warped image * \param[in] img2 Warped image
* \param[in,out] res Map from img1 to img2, stored in a smart pointer. If present as input, * \param[in] If present, it is an initial rough estimation that the mapper will try to refine.
* it is an initial rough estimation that the mapper will try to refine. * \return Map from img1 to img2, stored in a smart pointer.
*/ */
virtual void calculate(const cv::Mat& img1, const cv::Mat& img2, cv::Ptr<Map>& res) const = 0; CV_WRAP virtual cv::Ptr<Map> calculate(InputArray img1, InputArray img2, cv::Ptr<Map> init = cv::Ptr<Map>()) const = 0;
/* /*
* Returns a map compatible with the Mapper class * Returns a map compatible with the Mapper class
* \return Pointer to identity Map * \return Pointer to identity Map
*/ */
virtual cv::Ptr<Map> getMap(void) const = 0; CV_WRAP virtual cv::Ptr<Map> getMap() const = 0;
protected: protected:
/* /*
......
...@@ -49,15 +49,15 @@ namespace reg { ...@@ -49,15 +49,15 @@ namespace reg {
/*! /*!
* Mapper for affine motion * Mapper for affine motion
*/ */
class CV_EXPORTS MapperGradAffine: public Mapper class CV_EXPORTS_W MapperGradAffine: public Mapper
{ {
public: public:
MapperGradAffine(void); CV_WRAP MapperGradAffine();
~MapperGradAffine(void); ~MapperGradAffine(void);
virtual void calculate(const cv::Mat& img1, const cv::Mat& img2, cv::Ptr<Map>& res) const; CV_WRAP virtual cv::Ptr<Map> calculate(InputArray img1, InputArray img2, cv::Ptr<Map> init = cv::Ptr<Map>()) const;
cv::Ptr<Map> getMap(void) const; CV_WRAP cv::Ptr<Map> getMap() const;
}; };
//! @} //! @}
......
...@@ -49,15 +49,15 @@ namespace reg { ...@@ -49,15 +49,15 @@ namespace reg {
/*! /*!
* Mapper for euclidean motion: rotation plus shift * Mapper for euclidean motion: rotation plus shift
*/ */
class CV_EXPORTS MapperGradEuclid: public Mapper class CV_EXPORTS_W MapperGradEuclid: public Mapper
{ {
public: public:
MapperGradEuclid(void); CV_WRAP MapperGradEuclid();
~MapperGradEuclid(void); ~MapperGradEuclid();
virtual void calculate(const cv::Mat& img1, const cv::Mat& img2, cv::Ptr<Map>& res) const; CV_WRAP virtual cv::Ptr<Map> calculate(InputArray img1, InputArray img2, cv::Ptr<Map> init = cv::Ptr<Map>()) const;
cv::Ptr<Map> getMap(void) const; CV_WRAP cv::Ptr<Map> getMap() const;
}; };
//! @} //! @}
......
...@@ -49,15 +49,15 @@ namespace reg { ...@@ -49,15 +49,15 @@ namespace reg {
/*! /*!
* Gradient mapper for a projective transformation * Gradient mapper for a projective transformation
*/ */
class CV_EXPORTS MapperGradProj: public Mapper class CV_EXPORTS_W MapperGradProj: public Mapper
{ {
public: public:
MapperGradProj(void); CV_WRAP MapperGradProj();
~MapperGradProj(void); ~MapperGradProj();
virtual void calculate(const cv::Mat& img1, const cv::Mat& img2, cv::Ptr<Map>& res) const; CV_WRAP virtual cv::Ptr<Map> calculate(InputArray img1, InputArray img2, cv::Ptr<Map> init = cv::Ptr<Map>()) const;
cv::Ptr<Map> getMap(void) const; CV_WRAP cv::Ptr<Map> getMap() const;
}; };
//! @} //! @}
......
...@@ -49,15 +49,15 @@ namespace reg { ...@@ -49,15 +49,15 @@ namespace reg {
/*! /*!
* Gradient mapper for a translation * Gradient mapper for a translation
*/ */
class CV_EXPORTS MapperGradShift: public Mapper class CV_EXPORTS_W MapperGradShift: public Mapper
{ {
public: public:
MapperGradShift(void); CV_WRAP MapperGradShift();
virtual ~MapperGradShift(void); virtual ~MapperGradShift();
virtual void calculate(const cv::Mat& img1, const cv::Mat& img2, cv::Ptr<Map>& res) const; CV_WRAP virtual cv::Ptr<Map> calculate(InputArray img1, InputArray img2, cv::Ptr<Map> init = cv::Ptr<Map>()) const;
cv::Ptr<Map> getMap(void) const; CV_WRAP cv::Ptr<Map> getMap() const;
}; };
//! @} //! @}
......
...@@ -49,15 +49,15 @@ namespace reg { ...@@ -49,15 +49,15 @@ namespace reg {
/*! /*!
* Calculates a similarity transformation between to images (scale, rotation, and shift) * Calculates a similarity transformation between to images (scale, rotation, and shift)
*/ */
class CV_EXPORTS MapperGradSimilar: public Mapper class CV_EXPORTS_W MapperGradSimilar: public Mapper
{ {
public: public:
MapperGradSimilar(void); CV_WRAP MapperGradSimilar();
~MapperGradSimilar(void); ~MapperGradSimilar();
virtual void calculate(const cv::Mat& img1, const cv::Mat& img2, cv::Ptr<Map>& res) const; CV_WRAP virtual cv::Ptr<Map> calculate(InputArray img1, InputArray img2, cv::Ptr<Map> init = cv::Ptr<Map>()) const;
cv::Ptr<Map> getMap(void) const; CV_WRAP cv::Ptr<Map> getMap() const;
}; };
//! @} //! @}
......
...@@ -39,7 +39,9 @@ ...@@ -39,7 +39,9 @@
#define MAPPERPYRAMID_H_ #define MAPPERPYRAMID_H_
#include "mapper.hpp" #include "mapper.hpp"
#include "mapaffine.hpp"
#include "mapprojec.hpp"
#include "mapshift.hpp"
namespace cv { namespace cv {
namespace reg { namespace reg {
...@@ -50,27 +52,52 @@ namespace reg { ...@@ -50,27 +52,52 @@ namespace reg {
/*! /*!
* Calculates a map using a gaussian pyramid * Calculates a map using a gaussian pyramid
*/ */
class CV_EXPORTS MapperPyramid: public Mapper class CV_EXPORTS_W MapperPyramid: public Mapper
{ {
public: public:
/* /*
* Constructor * Constructor
* \param[in] baseMapper Base mapper used for the refinements * \param[in] baseMapper Base mapper used for the refinements
*/ */
MapperPyramid(const Mapper& baseMapper); CV_WRAP MapperPyramid(Ptr<Mapper> baseMapper);
void calculate(const cv::Mat& img1, const cv::Mat& img2, cv::Ptr<Map>& res) const; CV_WRAP virtual cv::Ptr<Map> calculate(InputArray img1, InputArray img2, cv::Ptr<Map> init = cv::Ptr<Map>()) const;
cv::Ptr<Map> getMap(void) const; CV_WRAP cv::Ptr<Map> getMap() const;
unsigned numLev_; /*!< Number of levels of the pyramid */ CV_PROP_RW int numLev_; /*!< Number of levels of the pyramid */
unsigned numIterPerScale_; /*!< Number of iterations at a given scale of the pyramid */ CV_PROP_RW int numIterPerScale_; /*!< Number of iterations at a given scale of the pyramid */
private: private:
MapperPyramid& operator=(const MapperPyramid&); MapperPyramid& operator=(const MapperPyramid&);
const Mapper& baseMapper_; /*!< Mapper used in inner level */ const Mapper& baseMapper_; /*!< Mapper used in inner level */
}; };
/*!
* Converts a pointer to a Map returned by MapperPyramid::calculate into the specified Map pointer type
*/
class CV_EXPORTS_W MapTypeCaster
{
public:
CV_WRAP static Ptr<MapAffine> toAffine(Ptr<Map> sourceMap)
{
MapAffine& affineMap = dynamic_cast<MapAffine&>(*sourceMap);
return Ptr<MapAffine>(new MapAffine(affineMap));
}
CV_WRAP static Ptr<MapShift> toShift(Ptr<Map> sourceMap)
{
MapShift& shiftMap = dynamic_cast<MapShift&>(*sourceMap);
return Ptr<MapShift>(new MapShift(shiftMap));
}
CV_WRAP static Ptr<MapProjec> toProjec(Ptr<Map> sourceMap)
{
MapProjec& projecMap = dynamic_cast<MapProjec&>(*sourceMap);
return Ptr<MapProjec>(new MapProjec(projecMap));
}
};
//! @} //! @}
}} // namespace cv::reg }} // namespace cv::reg
......
...@@ -50,13 +50,13 @@ namespace reg { ...@@ -50,13 +50,13 @@ namespace reg {
/*! /*!
* Defines an transformation that consists on a projective transformation * Defines an transformation that consists on a projective transformation
*/ */
class CV_EXPORTS MapProjec : public Map class CV_EXPORTS_W MapProjec : public Map
{ {
public: public:
/*! /*!
* Default constructor builds an identity map * Default constructor builds an identity map
*/ */
MapProjec(void); CV_WRAP MapProjec();
/*! /*!
* Constructor providing explicit values * Constructor providing explicit values
...@@ -67,15 +67,15 @@ public: ...@@ -67,15 +67,15 @@ public:
/*! /*!
* Destructor * Destructor
*/ */
~MapProjec(void); ~MapProjec();
void inverseWarp(const cv::Mat& img1, cv::Mat& img2) const; CV_WRAP void inverseWarp(InputArray img1, OutputArray img2) const;
cv::Ptr<Map> inverseMap(void) const; CV_WRAP cv::Ptr<Map> inverseMap() const;
void compose(const Map& map); CV_WRAP void compose(cv::Ptr<Map> map);
void scale(double factor); CV_WRAP void scale(double factor);
/*! /*!
* Returns projection matrix * Returns projection matrix
...@@ -85,10 +85,14 @@ public: ...@@ -85,10 +85,14 @@ public:
return projTr_; return projTr_;
} }
CV_WRAP void getProjTr(OutputArray projTr) const {
Mat(projTr_).copyTo(projTr);
}
/*! /*!
* Normalizes object's homography * Normalizes object's homography
*/ */
void normalize(void) { CV_WRAP void normalize() {
double z = 1./projTr_(2, 2); double z = 1./projTr_(2, 2);
for(size_t v_i = 0; v_i < sizeof(projTr_.val)/sizeof(projTr_.val[0]); ++v_i) for(size_t v_i = 0; v_i < sizeof(projTr_.val)/sizeof(projTr_.val[0]); ++v_i)
projTr_.val[v_i] *= z; projTr_.val[v_i] *= z;
......
...@@ -50,32 +50,33 @@ namespace reg { ...@@ -50,32 +50,33 @@ namespace reg {
/*! /*!
* Defines an transformation that consists on a simple displacement * Defines an transformation that consists on a simple displacement
*/ */
class CV_EXPORTS MapShift : public Map class CV_EXPORTS_W MapShift : public Map
{ {
public: public:
/*! /*!
* Default constructor builds an identity map * Default constructor builds an identity map
*/ */
MapShift(void); CV_WRAP MapShift();
/*! /*!
* Constructor providing explicit values * Constructor providing explicit values
* \param[in] shift Displacement * \param[in] shift Displacement
*/ */
MapShift(const cv::Vec<double, 2>& shift);
CV_WRAP MapShift(InputArray shift);
/*! /*!
* Destructor * Destructor
*/ */
~MapShift(void); ~MapShift();
void inverseWarp(const cv::Mat& img1, cv::Mat& img2) const; CV_WRAP void inverseWarp(InputArray img1, OutputArray img2) const;
cv::Ptr<Map> inverseMap(void) const; CV_WRAP cv::Ptr<Map> inverseMap() const;
void compose(const Map& map); CV_WRAP void compose(cv::Ptr<Map> map);
void scale(double factor); CV_WRAP void scale(double factor);
/*! /*!
* Return displacement * Return displacement
...@@ -85,6 +86,10 @@ public: ...@@ -85,6 +86,10 @@ public:
return shift_; return shift_;
} }
CV_WRAP void getShift(OutputArray shift) const {
Mat(shift_).copyTo(shift);
}
private: private:
cv::Vec<double, 2> shift_; /*< Displacement */ cv::Vec<double, 2> shift_; /*< Displacement */
}; };
......
...@@ -72,10 +72,9 @@ Vec<double, 2> perfShift(const Mat& img1) ...@@ -72,10 +72,9 @@ Vec<double, 2> perfShift(const Mat& img1)
mapTest.warp(img1, img2); mapTest.warp(img1, img2);
// Register // Register
MapperGradShift mapper; Ptr<MapperGradShift> mapper = makePtr<MapperGradShift>();
MapperPyramid mappPyr(mapper); MapperPyramid mappPyr(mapper);
Ptr<Map> mapPtr; Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
mappPyr.calculate(img1, img2, mapPtr);
MapShift* mapShift = dynamic_cast<MapShift*>(mapPtr.get()); MapShift* mapShift = dynamic_cast<MapShift*>(mapPtr.get());
return mapShift->getShift(); return mapShift->getShift();
...@@ -96,10 +95,9 @@ Matx<double, 2, 6> perfEuclidean(const Mat& img1) ...@@ -96,10 +95,9 @@ Matx<double, 2, 6> perfEuclidean(const Mat& img1)
mapTest.warp(img1, img2); mapTest.warp(img1, img2);
// Register // Register
MapperGradEuclid mapper; Ptr<MapperGradEuclid> mapper = makePtr<MapperGradEuclid>();
MapperPyramid mappPyr(mapper); MapperPyramid mappPyr(mapper);
Ptr<Map> mapPtr; Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
mappPyr.calculate(img1, img2, mapPtr);
MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get()); MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get());
Matx<double, 2, 2> resLinTr = mapAff->getLinTr(); Matx<double, 2, 2> resLinTr = mapAff->getLinTr();
...@@ -127,10 +125,9 @@ Matx<double, 2, 6> perfSimilarity(const Mat& img1) ...@@ -127,10 +125,9 @@ Matx<double, 2, 6> perfSimilarity(const Mat& img1)
mapTest.warp(img1, img2); mapTest.warp(img1, img2);
// Register // Register
MapperGradSimilar mapper; Ptr<MapperGradSimilar> mapper = makePtr<MapperGradSimilar>();
MapperPyramid mappPyr(mapper); MapperPyramid mappPyr(mapper);
Ptr<Map> mapPtr; Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
mappPyr.calculate(img1, img2, mapPtr);
MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get()); MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get());
Matx<double, 2, 2> resLinTr = mapAff->getLinTr(); Matx<double, 2, 2> resLinTr = mapAff->getLinTr();
...@@ -154,10 +151,9 @@ Matx<double, 2, 6> perfAffine(const Mat& img1) ...@@ -154,10 +151,9 @@ Matx<double, 2, 6> perfAffine(const Mat& img1)
mapTest.warp(img1, img2); mapTest.warp(img1, img2);
// Register // Register
MapperGradAffine mapper; Ptr<MapperGradAffine> mapper = makePtr<MapperGradAffine>();
MapperPyramid mappPyr(mapper); MapperPyramid mappPyr(mapper);
Ptr<Map> mapPtr; Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
mappPyr.calculate(img1, img2, mapPtr);
MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get()); MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get());
Matx<double, 2, 2> resLinTr = mapAff->getLinTr(); Matx<double, 2, 2> resLinTr = mapAff->getLinTr();
...@@ -179,10 +175,9 @@ Matx<double, 3, 3> perfProjective(const Mat& img1) ...@@ -179,10 +175,9 @@ Matx<double, 3, 3> perfProjective(const Mat& img1)
mapTest.warp(img1, img2); mapTest.warp(img1, img2);
// Register // Register
MapperGradProj mapper; Ptr<MapperGradProj> mapper = makePtr<MapperGradProj>();
MapperPyramid mappPyr(mapper); MapperPyramid mappPyr(mapper);
Ptr<Map> mapPtr; Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
mappPyr.calculate(img1, img2, mapPtr);
MapProjec* mapProj = dynamic_cast<MapProjec*>(mapPtr.get()); MapProjec* mapProj = dynamic_cast<MapProjec*>(mapPtr.get());
mapProj->normalize(); mapProj->normalize();
......
...@@ -99,10 +99,9 @@ static void testShift(const Mat& img1) ...@@ -99,10 +99,9 @@ static void testShift(const Mat& img1)
showDifference(img1, img2, DIFF_IM); showDifference(img1, img2, DIFF_IM);
// Register // Register
MapperGradShift mapper; Ptr<MapperGradShift> mapper = makePtr<MapperGradShift>();
MapperPyramid mappPyr(mapper); MapperPyramid mappPyr(mapper);
Ptr<Map> mapPtr; Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
mappPyr.calculate(img1, img2, mapPtr);
// Print result // Print result
MapShift* mapShift = dynamic_cast<MapShift*>(mapPtr.get()); MapShift* mapShift = dynamic_cast<MapShift*>(mapPtr.get());
...@@ -135,10 +134,9 @@ static void testEuclidean(const Mat& img1) ...@@ -135,10 +134,9 @@ static void testEuclidean(const Mat& img1)
showDifference(img1, img2, DIFF_IM); showDifference(img1, img2, DIFF_IM);
// Register // Register
MapperGradEuclid mapper; Ptr<MapperGradEuclid> mapper = makePtr<MapperGradEuclid>();
MapperPyramid mappPyr(mapper); MapperPyramid mappPyr(mapper);
Ptr<Map> mapPtr; Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
mappPyr.calculate(img1, img2, mapPtr);
// Print result // Print result
MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get()); MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get());
...@@ -174,10 +172,9 @@ static void testSimilarity(const Mat& img1) ...@@ -174,10 +172,9 @@ static void testSimilarity(const Mat& img1)
showDifference(img1, img2, DIFF_IM); showDifference(img1, img2, DIFF_IM);
// Register // Register
MapperGradSimilar mapper; Ptr<MapperGradSimilar> mapper = makePtr<MapperGradSimilar>();
MapperPyramid mappPyr(mapper); MapperPyramid mappPyr(mapper);
Ptr<Map> mapPtr; Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
mappPyr.calculate(img1, img2, mapPtr);
// Print result // Print result
MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get()); MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get());
...@@ -209,10 +206,9 @@ static void testAffine(const Mat& img1) ...@@ -209,10 +206,9 @@ static void testAffine(const Mat& img1)
showDifference(img1, img2, DIFF_IM); showDifference(img1, img2, DIFF_IM);
// Register // Register
MapperGradAffine mapper; Ptr<MapperGradAffine> mapper = makePtr<MapperGradAffine>();
MapperPyramid mappPyr(mapper); MapperPyramid mappPyr(mapper);
Ptr<Map> mapPtr; Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
mappPyr.calculate(img1, img2, mapPtr);
// Print result // Print result
MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get()); MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get());
...@@ -243,10 +239,9 @@ static void testProjective(const Mat& img1) ...@@ -243,10 +239,9 @@ static void testProjective(const Mat& img1)
showDifference(img1, img2, DIFF_IM); showDifference(img1, img2, DIFF_IM);
// Register // Register
MapperGradProj mapper; Ptr<MapperGradProj> mapper = makePtr<MapperGradProj>();
MapperPyramid mappPyr(mapper); MapperPyramid mappPyr(mapper);
Ptr<Map> mapPtr; Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
mappPyr.calculate(img1, img2, mapPtr);
// Print result // Print result
MapProjec* mapProj = dynamic_cast<MapProjec*>(mapPtr.get()); MapProjec* mapProj = dynamic_cast<MapProjec*>(mapPtr.get());
...@@ -347,7 +342,7 @@ static void calcHomographyFeature(const Mat& image1, const Mat& image2) ...@@ -347,7 +342,7 @@ static void calcHomographyFeature(const Mat& image1, const Mat& image2)
warpPerspective(image2, result, Hinv, image1.size()); warpPerspective(image2, result, Hinv, image1.size());
cout << "--- Feature method\n" << H << endl; cout << "--- Feature method\n" << H << endl;
Mat imf1, resf; Mat imf1, resf;
image1.convertTo(imf1, CV_64FC3); image1.convertTo(imf1, CV_64FC3);
result.convertTo(resf, CV_64FC3); result.convertTo(resf, CV_64FC3);
...@@ -359,10 +354,9 @@ static void calcHomographyPixel(const Mat& img1, const Mat& img2) ...@@ -359,10 +354,9 @@ static void calcHomographyPixel(const Mat& img1, const Mat& img2)
static const char* diffpixel = "Difference pixel registered"; static const char* diffpixel = "Difference pixel registered";
// Register using pixel differences // Register using pixel differences
MapperGradProj mapper; Ptr<MapperGradProj> mapper = makePtr<MapperGradProj>();
MapperPyramid mappPyr(mapper); MapperPyramid mappPyr(mapper);
Ptr<Map> mapPtr; Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
mappPyr.calculate(img1, img2, mapPtr);
// Print result // Print result
MapProjec* mapProj = dynamic_cast<MapProjec*>(mapPtr.get()); MapProjec* mapProj = dynamic_cast<MapProjec*>(mapPtr.get());
...@@ -398,7 +392,7 @@ static void comparePixelVsFeature(const Mat& img1_8b, const Mat& img2_8b) ...@@ -398,7 +392,7 @@ static void comparePixelVsFeature(const Mat& img1_8b, const Mat& img2_8b)
int main(void) int main(void)
{ {
Mat img1; Mat img1;
img1 = imread("home.png", CV_LOAD_IMAGE_UNCHANGED); img1 = imread("home.png", CV_LOAD_IMAGE_UNCHANGED);
if(!img1.data) { if(!img1.data) {
cout << "Could not open or find file" << endl; cout << "Could not open or find file" << endl;
......
#!/usr/bin/python
import cv2
import numpy as np
import sys
img1 = cv2.imread(sys.argv[1])
img1 = img1.astype(np.float32)
shift = np.array([5., 5.])
mapTest = cv2.reg.MapShift(shift)
img2 = mapTest.warp(img1)
mapper = cv2.reg.MapperGradShift()
mappPyr = cv2.reg.MapperPyramid(mapper)
resMap = mappPyr.calculate(img1, img2)
mapShift = cv2.reg.MapTypeCaster_toShift(resMap)
print(mapShift.getShift())
...@@ -44,12 +44,12 @@ namespace reg { ...@@ -44,12 +44,12 @@ namespace reg {
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
Map::~Map(void) Map::~Map()
{ {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void Map::warp(const Mat& img1, Mat& img2) const void Map::warp(InputArray img1, OutputArray img2) const
{ {
Ptr<Map> invMap(inverseMap()); Ptr<Map> invMap(inverseMap());
invMap->inverseWarp(img1, img2); invMap->inverseWarp(img1, img2);
......
...@@ -45,7 +45,7 @@ namespace reg { ...@@ -45,7 +45,7 @@ namespace reg {
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapAffine::MapAffine(void) MapAffine::MapAffine()
: linTr_(Matx<double, 2, 2>::eye()), shift_() : linTr_(Matx<double, 2, 2>::eye()), shift_()
{ {
} }
...@@ -57,13 +57,14 @@ MapAffine::MapAffine(const Matx<double, 2, 2>& linTr, const Vec<double, 2>& shif ...@@ -57,13 +57,14 @@ MapAffine::MapAffine(const Matx<double, 2, 2>& linTr, const Vec<double, 2>& shif
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapAffine::~MapAffine(void) MapAffine::~MapAffine()
{ {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void MapAffine::inverseWarp(const Mat& img1, Mat& img2) const void MapAffine::inverseWarp(InputArray _img1, OutputArray img2) const
{ {
Mat img1 = _img1.getMat();
// Rows and columns in destination // Rows and columns in destination
Mat dest_r, dest_c; Mat dest_r, dest_c;
dest_r.create(img1.size(), CV_32FC1); dest_r.create(img1.size(), CV_32FC1);
...@@ -93,10 +94,10 @@ Ptr<Map> MapAffine::inverseMap(void) const ...@@ -93,10 +94,10 @@ Ptr<Map> MapAffine::inverseMap(void) const
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void MapAffine::compose(const Map& map) void MapAffine::compose(cv::Ptr<Map> map)
{ {
// Composition of affine transformations T and T' is (T o T') = A'Ax + A'b + b' // Composition of affine transformations T and T' is (T o T') = A'Ax + A'b + b'
const MapAffine& mapAff = static_cast<const MapAffine&>(map); const MapAffine& mapAff = static_cast<const MapAffine&>(*map);
Matx<double, 2, 2> compMat = mapAff.getLinTr()*linTr_; Matx<double, 2, 2> compMat = mapAff.getLinTr()*linTr_;
Vec<double, 2> compShift = mapAff.getLinTr()*shift_ + mapAff.getShift(); Vec<double, 2> compShift = mapAff.getLinTr()*shift_ + mapAff.getShift();
linTr_ = compMat; linTr_ = compMat;
......
...@@ -59,28 +59,45 @@ void Mapper::gradient(const Mat& img1, const Mat& img2, Mat& Ix, Mat& Iy, Mat& I ...@@ -59,28 +59,45 @@ void Mapper::gradient(const Mat& img1, const Mat& img2, Mat& Ix, Mat& Iy, Mat& I
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void Mapper::grid(const Mat& img, Mat& grid_r, Mat& grid_c) const
template<typename _Tp>
void fillGridMatrices(const Mat img, Mat grid_r, Mat grid_c)
{ {
// Matrices with reference frame coordinates
grid_r.create(img.size(), img.type());
grid_c.create(img.size(), img.type());
if(img.channels() == 1) { if(img.channels() == 1) {
for(int r_i = 0; r_i < img.rows; ++r_i) { for(int r_i = 0; r_i < img.rows; ++r_i) {
for(int c_i = 0; c_i < img.cols; ++c_i) { for(int c_i = 0; c_i < img.cols; ++c_i) {
grid_r.at<double>(r_i, c_i) = r_i; grid_r.at<_Tp>(r_i, c_i) = (_Tp)r_i;
grid_c.at<double>(r_i, c_i) = c_i; grid_c.at<_Tp>(r_i, c_i) = (_Tp)c_i;
} }
} }
} else { } else {
Vec3d ones(1., 1., 1.); Vec<_Tp, 3> ones((_Tp)1, (_Tp)1, (_Tp)1);
for(int r_i = 0; r_i < img.rows; ++r_i) { for(int r_i = 0; r_i < img.rows; ++r_i) {
for(int c_i = 0; c_i < img.cols; ++c_i) { for(int c_i = 0; c_i < img.cols; ++c_i) {
grid_r.at<Vec3d>(r_i, c_i) = r_i*ones; grid_r.at< Vec<_Tp, 3> >(r_i, c_i) = (_Tp)r_i*ones;
grid_c.at<Vec3d>(r_i, c_i) = c_i*ones; grid_c.at< Vec<_Tp, 3> >(r_i, c_i) = (_Tp)c_i*ones;
} }
} }
} }
} }
void Mapper::grid(const Mat& img, Mat& grid_r, Mat& grid_c) const
{
CV_DbgAssert(img.channels() == 1 || img.channels() == 3);
// Matrices with reference frame coordinates
grid_r.create(img.size(), img.type());
grid_c.create(img.size(), img.type());
if(img.depth() == CV_8U)
fillGridMatrices<uchar>(img, grid_r, grid_c);
if(img.depth() == CV_16U)
fillGridMatrices<ushort>(img, grid_r, grid_c);
else if(img.depth() == CV_32F)
fillGridMatrices<float>(img, grid_r, grid_c);
else if(img.depth() == CV_64F)
fillGridMatrices<double>(img, grid_r, grid_c);
}
}} // namespace cv::reg }} // namespace cv::reg
...@@ -44,21 +44,21 @@ namespace reg { ...@@ -44,21 +44,21 @@ namespace reg {
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapperGradAffine::MapperGradAffine(void) MapperGradAffine::MapperGradAffine()
{ {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapperGradAffine::~MapperGradAffine(void) MapperGradAffine::~MapperGradAffine()
{ {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void MapperGradAffine::calculate( cv::Ptr<Map> MapperGradAffine::calculate(InputArray _img1, InputArray image2, cv::Ptr<Map> init) const
const cv::Mat& img1, const cv::Mat& image2, cv::Ptr<Map>& res) const
{ {
Mat img1 = _img1.getMat();
Mat gradx, grady, imgDiff; Mat gradx, grady, imgDiff;
Mat img2; Mat img2;
...@@ -66,11 +66,11 @@ void MapperGradAffine::calculate( ...@@ -66,11 +66,11 @@ void MapperGradAffine::calculate(
CV_DbgAssert(img1.channels() == image2.channels()); CV_DbgAssert(img1.channels() == image2.channels());
CV_DbgAssert(img1.channels() == 1 || img1.channels() == 3); CV_DbgAssert(img1.channels() == 1 || img1.channels() == 3);
if(!res.empty()) { if(!init.empty()) {
// We have initial values for the registration: we move img2 to that initial reference // We have initial values for the registration: we move img2 to that initial reference
res->inverseWarp(image2, img2); init->inverseWarp(image2, img2);
} else { } else {
img2 = image2; img2 = image2.getMat();
} }
// Get gradient in all channels // Get gradient in all channels
...@@ -145,16 +145,19 @@ void MapperGradAffine::calculate( ...@@ -145,16 +145,19 @@ void MapperGradAffine::calculate(
Matx<double, 2, 2> linTr(k(0) + 1., k(1), k(3), k(4) + 1.); Matx<double, 2, 2> linTr(k(0) + 1., k(1), k(3), k(4) + 1.);
Vec<double, 2> shift(k(2), k(5)); Vec<double, 2> shift(k(2), k(5));
if(res.empty()) { if(init.empty()) {
res = Ptr<Map>(new MapAffine(linTr, shift)); return Ptr<Map>(new MapAffine(linTr, shift));
} else { } else {
MapAffine newTr(linTr, shift); Ptr<MapAffine> newTr(new MapAffine(linTr, shift));
res->compose(newTr); MapAffine* initPtr = dynamic_cast<MapAffine*>(init.get());
Ptr<MapAffine> oldTr(new MapAffine(initPtr->getLinTr(), initPtr->getShift()));
oldTr->compose(newTr);
return oldTr;
} }
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
cv::Ptr<Map> MapperGradAffine::getMap(void) const cv::Ptr<Map> MapperGradAffine::getMap() const
{ {
return cv::Ptr<Map>(new MapAffine()); return cv::Ptr<Map>(new MapAffine());
} }
......
...@@ -44,21 +44,22 @@ namespace reg { ...@@ -44,21 +44,22 @@ namespace reg {
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapperGradEuclid::MapperGradEuclid(void) MapperGradEuclid::MapperGradEuclid()
{ {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapperGradEuclid::~MapperGradEuclid(void) MapperGradEuclid::~MapperGradEuclid()
{ {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void MapperGradEuclid::calculate( cv::Ptr<Map> MapperGradEuclid::calculate(
const cv::Mat& img1, const cv::Mat& image2, cv::Ptr<Map>& res) const InputArray _img1, InputArray image2, cv::Ptr<Map> init) const
{ {
Mat img1 = _img1.getMat();
Mat gradx, grady, imgDiff; Mat gradx, grady, imgDiff;
Mat img2; Mat img2;
...@@ -66,11 +67,11 @@ void MapperGradEuclid::calculate( ...@@ -66,11 +67,11 @@ void MapperGradEuclid::calculate(
CV_DbgAssert(img1.channels() == image2.channels()); CV_DbgAssert(img1.channels() == image2.channels());
CV_DbgAssert(img1.channels() == 1 || img1.channels() == 3); CV_DbgAssert(img1.channels() == 1 || img1.channels() == 3);
if(!res.empty()) { if(!init.empty()) {
// We have initial values for the registration: we move img2 to that initial reference // We have initial values for the registration: we move img2 to that initial reference
res->inverseWarp(image2, img2); init->inverseWarp(image2, img2);
} else { } else {
img2 = image2; img2 = image2.getMat();
} }
// Matrices with reference frame coordinates // Matrices with reference frame coordinates
...@@ -111,16 +112,19 @@ void MapperGradEuclid::calculate( ...@@ -111,16 +112,19 @@ void MapperGradEuclid::calculate(
Matx<double, 2, 2> linTr(cosT, -sinT, sinT, cosT); Matx<double, 2, 2> linTr(cosT, -sinT, sinT, cosT);
Vec<double, 2> shift(k(0), k(1)); Vec<double, 2> shift(k(0), k(1));
if(res.empty()) { if(init.empty()) {
res = Ptr<Map>(new MapAffine(linTr, shift)); return Ptr<Map>(new MapAffine(linTr, shift));
} else { } else {
MapAffine newTr(linTr, shift); Ptr<MapAffine> newTr(new MapAffine(linTr, shift));
res->compose(newTr); MapAffine* initPtr = dynamic_cast<MapAffine*>(init.get());
Ptr<MapAffine> oldTr(new MapAffine(initPtr->getLinTr(), initPtr->getShift()));
oldTr->compose(newTr);
return oldTr;
} }
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
cv::Ptr<Map> MapperGradEuclid::getMap(void) const cv::Ptr<Map> MapperGradEuclid::getMap() const
{ {
return cv::Ptr<Map>(new MapAffine()); return cv::Ptr<Map>(new MapAffine());
} }
......
...@@ -44,21 +44,22 @@ namespace reg { ...@@ -44,21 +44,22 @@ namespace reg {
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapperGradProj::MapperGradProj(void) MapperGradProj::MapperGradProj()
{ {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapperGradProj::~MapperGradProj(void) MapperGradProj::~MapperGradProj()
{ {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void MapperGradProj::calculate( cv::Ptr<Map> MapperGradProj::calculate(
const cv::Mat& img1, const cv::Mat& image2, cv::Ptr<Map>& res) const InputArray _img1, InputArray image2, cv::Ptr<Map> init) const
{ {
Mat img1 = _img1.getMat();
Mat gradx, grady, imgDiff; Mat gradx, grady, imgDiff;
Mat img2; Mat img2;
...@@ -66,11 +67,11 @@ void MapperGradProj::calculate( ...@@ -66,11 +67,11 @@ void MapperGradProj::calculate(
CV_DbgAssert(img1.channels() == image2.channels()); CV_DbgAssert(img1.channels() == image2.channels());
CV_DbgAssert(img1.channels() == 1 || img1.channels() == 3); CV_DbgAssert(img1.channels() == 1 || img1.channels() == 3);
if(!res.empty()) { if(!init.empty()) {
// We have initial values for the registration: we move img2 to that initial reference // We have initial values for the registration: we move img2 to that initial reference
res->inverseWarp(image2, img2); init->inverseWarp(image2, img2);
} else { } else {
img2 = image2; img2 = image2.getMat();
} }
// Get gradient in all channels // Get gradient in all channels
...@@ -195,16 +196,19 @@ void MapperGradProj::calculate( ...@@ -195,16 +196,19 @@ void MapperGradProj::calculate(
Vec<double, 8> k = A.inv(DECOMP_CHOLESKY)*b; Vec<double, 8> k = A.inv(DECOMP_CHOLESKY)*b;
Matx<double, 3, 3> H(k(0) + 1., k(1), k(2), k(3), k(4) + 1., k(5), k(6), k(7), 1.); Matx<double, 3, 3> H(k(0) + 1., k(1), k(2), k(3), k(4) + 1., k(5), k(6), k(7), 1.);
if(res.empty()) { if(init.empty()) {
res = Ptr<Map>(new MapProjec(H)); return Ptr<Map>(new MapProjec(H));
} else { } else {
MapProjec newTr(H); Ptr<MapProjec> newTr(new MapProjec(H));
res->compose(newTr); MapProjec* initPtr = dynamic_cast<MapProjec*>(init.get());
Ptr<MapProjec> oldTr(new MapProjec(initPtr->getProjTr()));
oldTr->compose(newTr);
return oldTr;
} }
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
cv::Ptr<Map> MapperGradProj::getMap(void) const cv::Ptr<Map> MapperGradProj::getMap() const
{ {
return cv::Ptr<Map>(new MapProjec()); return cv::Ptr<Map>(new MapProjec());
} }
......
...@@ -44,31 +44,32 @@ namespace reg { ...@@ -44,31 +44,32 @@ namespace reg {
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapperGradShift::MapperGradShift(void) MapperGradShift::MapperGradShift()
{ {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapperGradShift::~MapperGradShift(void) MapperGradShift::~MapperGradShift()
{ {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void MapperGradShift::calculate( cv::Ptr<Map> MapperGradShift::calculate(
const cv::Mat& img1, const cv::Mat& image2, cv::Ptr<Map>& res) const InputArray _img1, InputArray image2, cv::Ptr<Map> init) const
{ {
Mat img1 = _img1.getMat();
Mat gradx, grady, imgDiff; Mat gradx, grady, imgDiff;
Mat img2; Mat img2;
CV_DbgAssert(img1.size() == image2.size()); CV_DbgAssert(img1.size() == image2.size());
if(!res.empty()) { if(!init.empty()) {
// We have initial values for the registration: we move img2 to that initial reference // We have initial values for the registration: we move img2 to that initial reference
res->inverseWarp(image2, img2); init->inverseWarp(image2, img2);
} else { } else {
img2 = image2; img2 = image2.getMat();
} }
// Get gradient in all channels // Get gradient in all channels
...@@ -92,16 +93,19 @@ void MapperGradShift::calculate( ...@@ -92,16 +93,19 @@ void MapperGradShift::calculate(
// Calculate shift. We use Cholesky decomposition, as A is symmetric. // Calculate shift. We use Cholesky decomposition, as A is symmetric.
Vec<double, 2> shift = A.inv(DECOMP_CHOLESKY)*b; Vec<double, 2> shift = A.inv(DECOMP_CHOLESKY)*b;
if(res.empty()) { if(init.empty()) {
res = Ptr<Map>(new MapShift(shift)); return Ptr<Map>(new MapShift(shift));
} else { } else {
MapShift newTr(shift); Ptr<MapShift> newTr(new MapShift(shift));
res->compose(newTr); MapShift* initPtr = dynamic_cast<MapShift*>(init.get());
Ptr<MapShift> oldTr(new MapShift(initPtr->getShift()));
oldTr->compose(newTr);
return oldTr;
} }
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
cv::Ptr<Map> MapperGradShift::getMap(void) const cv::Ptr<Map> MapperGradShift::getMap() const
{ {
return cv::Ptr<Map>(new MapShift()); return cv::Ptr<Map>(new MapShift());
} }
......
...@@ -44,21 +44,22 @@ namespace reg { ...@@ -44,21 +44,22 @@ namespace reg {
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapperGradSimilar::MapperGradSimilar(void) MapperGradSimilar::MapperGradSimilar()
{ {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapperGradSimilar::~MapperGradSimilar(void) MapperGradSimilar::~MapperGradSimilar()
{ {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void MapperGradSimilar::calculate( cv::Ptr<Map> MapperGradSimilar::calculate(
const cv::Mat& img1, const cv::Mat& image2, cv::Ptr<Map>& res) const InputArray _img1, InputArray image2, cv::Ptr<Map> init) const
{ {
Mat img1 = _img1.getMat();
Mat gradx, grady, imgDiff; Mat gradx, grady, imgDiff;
Mat img2; Mat img2;
...@@ -66,11 +67,11 @@ void MapperGradSimilar::calculate( ...@@ -66,11 +67,11 @@ void MapperGradSimilar::calculate(
CV_DbgAssert(img1.channels() == image2.channels()); CV_DbgAssert(img1.channels() == image2.channels());
CV_DbgAssert(img1.channels() == 1 || img1.channels() == 3); CV_DbgAssert(img1.channels() == 1 || img1.channels() == 3);
if(!res.empty()) { if(!init.empty()) {
// We have initial values for the registration: we move img2 to that initial reference // We have initial values for the registration: we move img2 to that initial reference
res->inverseWarp(image2, img2); init->inverseWarp(image2, img2);
} else { } else {
img2 = image2; img2 = image2.getMat();
} }
// Get gradient in all channels // Get gradient in all channels
...@@ -126,16 +127,19 @@ void MapperGradSimilar::calculate( ...@@ -126,16 +127,19 @@ void MapperGradSimilar::calculate(
Matx<double, 2, 2> linTr(k(0) + 1., k(1), -k(1), k(0) + 1.); Matx<double, 2, 2> linTr(k(0) + 1., k(1), -k(1), k(0) + 1.);
Vec<double, 2> shift(k(2), k(3)); Vec<double, 2> shift(k(2), k(3));
if(res.empty()) { if(init.empty()) {
res = Ptr<Map>(new MapAffine(linTr, shift)); return Ptr<Map>(new MapAffine(linTr, shift));
} else { } else {
MapAffine newTr(linTr, shift); Ptr<MapAffine> newTr(new MapAffine(linTr, shift));
res->compose(newTr); MapAffine* initPtr = dynamic_cast<MapAffine*>(init.get());
Ptr<MapAffine> oldTr(new MapAffine(initPtr->getLinTr(), initPtr->getShift()));
oldTr->compose(newTr);
return oldTr;
} }
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
cv::Ptr<Map> MapperGradSimilar::getMap(void) const cv::Ptr<Map> MapperGradSimilar::getMap() const
{ {
return cv::Ptr<Map>(new MapAffine()); return cv::Ptr<Map>(new MapAffine());
} }
......
...@@ -48,22 +48,23 @@ namespace reg { ...@@ -48,22 +48,23 @@ namespace reg {
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapperPyramid::MapperPyramid(const Mapper& baseMapper) MapperPyramid::MapperPyramid(Ptr<Mapper> baseMapper)
: numLev_(3), numIterPerScale_(3), baseMapper_(baseMapper) : numLev_(3), numIterPerScale_(3), baseMapper_(*baseMapper)
{ {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void MapperPyramid::calculate(const Mat& img1, const Mat& image2, Ptr<Map>& res) const Ptr<Map> MapperPyramid::calculate(InputArray _img1, InputArray image2, Ptr<Map> init) const
{ {
Mat img1 = _img1.getMat();
Mat img2; Mat img2;
if(!res.empty()) { if(!init.empty()) {
// We have initial values for the registration: we move img2 to that initial reference // We have initial values for the registration: we move img2 to that initial reference
res->inverseWarp(image2, img2); init->inverseWarp(image2, img2);
} else { } else {
res = baseMapper_.getMap(); init = baseMapper_.getMap();
img2 = image2; img2 = image2.getMat();
} }
cv::Ptr<Map> ident = baseMapper_.getMap(); cv::Ptr<Map> ident = baseMapper_.getMap();
...@@ -72,29 +73,30 @@ void MapperPyramid::calculate(const Mat& img1, const Mat& image2, Ptr<Map>& res) ...@@ -72,29 +73,30 @@ void MapperPyramid::calculate(const Mat& img1, const Mat& image2, Ptr<Map>& res)
vector<Mat> pyrIm1(numLev_), pyrIm2(numLev_); vector<Mat> pyrIm1(numLev_), pyrIm2(numLev_);
pyrIm1[0] = img1; pyrIm1[0] = img1;
pyrIm2[0] = img2; pyrIm2[0] = img2;
for(size_t im_i = 1; im_i < numLev_; ++im_i) { for(int im_i = 1; im_i < numLev_; ++im_i) {
pyrDown(pyrIm1[im_i - 1], pyrIm1[im_i]); pyrDown(pyrIm1[im_i - 1], pyrIm1[im_i]);
pyrDown(pyrIm2[im_i - 1], pyrIm2[im_i]); pyrDown(pyrIm2[im_i - 1], pyrIm2[im_i]);
} }
Mat currRef, currImg; Mat currRef, currImg;
for(size_t lv_i = 0; lv_i < numLev_; ++lv_i) { for(int lv_i = 0; lv_i < numLev_; ++lv_i) {
currRef = pyrIm1[numLev_ - 1 - lv_i]; currRef = pyrIm1[numLev_ - 1 - lv_i];
currImg = pyrIm2[numLev_ - 1 - lv_i]; currImg = pyrIm2[numLev_ - 1 - lv_i];
// Scale the transformation as we are incresing the resolution in each iteration // Scale the transformation as we are incresing the resolution in each iteration
if(lv_i != 0) { if(lv_i != 0) {
ident->scale(2.); ident->scale(2.);
} }
for(size_t it_i = 0; it_i < numIterPerScale_; ++it_i) { for(int it_i = 0; it_i < numIterPerScale_; ++it_i) {
baseMapper_.calculate(currRef, currImg, ident); ident = baseMapper_.calculate(currRef, currImg, ident);
} }
} }
res->compose(*ident.get()); init->compose(ident);
return init;
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
cv::Ptr<Map> MapperPyramid::getMap(void) const cv::Ptr<Map> MapperPyramid::getMap() const
{ {
return cv::Ptr<Map>(); return cv::Ptr<Map>();
} }
......
...@@ -45,7 +45,7 @@ namespace reg { ...@@ -45,7 +45,7 @@ namespace reg {
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapProjec::MapProjec(void) MapProjec::MapProjec()
: projTr_(Matx<double, 3, 3>::eye()) : projTr_(Matx<double, 3, 3>::eye())
{ {
} }
...@@ -57,13 +57,14 @@ MapProjec::MapProjec(const Matx<double, 3, 3>& projTr) ...@@ -57,13 +57,14 @@ MapProjec::MapProjec(const Matx<double, 3, 3>& projTr)
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapProjec::~MapProjec(void) MapProjec::~MapProjec()
{ {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void MapProjec::inverseWarp(const Mat& img1, Mat& img2) const void MapProjec::inverseWarp(InputArray _img1, OutputArray img2) const
{ {
Mat img1 = _img1.getMat();
// Rows and columns in destination // Rows and columns in destination
Mat dest_r, dest_c; Mat dest_r, dest_c;
dest_r.create(img1.size(), CV_32FC1); dest_r.create(img1.size(), CV_32FC1);
...@@ -95,10 +96,10 @@ Ptr<Map> MapProjec::inverseMap(void) const ...@@ -95,10 +96,10 @@ Ptr<Map> MapProjec::inverseMap(void) const
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void MapProjec::compose(const Map& map) void MapProjec::compose(Ptr<Map> map)
{ {
// Composition of homographies H and H' is (H o H') = H'*H // Composition of homographies H and H' is (H o H') = H'*H
const MapProjec& mapProj = static_cast<const MapProjec&>(map); const MapProjec& mapProj = static_cast<const MapProjec&>(*map);
Matx<double, 3, 3> compProjTr = mapProj.getProjTr()*projTr_; Matx<double, 3, 3> compProjTr = mapProj.getProjTr()*projTr_;
projTr_ = compProjTr; projTr_ = compProjTr;
} }
......
...@@ -46,23 +46,26 @@ namespace reg { ...@@ -46,23 +46,26 @@ namespace reg {
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapShift::MapShift(void) : shift_() MapShift::MapShift() : shift_()
{ {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapShift::MapShift(const Vec<double, 2>& shift) : shift_(shift) MapShift::MapShift(InputArray shift)
{ {
Mat shiftMat = shift.getMat();
shiftMat.copyTo(shift_);
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
MapShift::~MapShift(void) MapShift::~MapShift()
{ {
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void MapShift::inverseWarp(const Mat& img1, Mat& img2) const void MapShift::inverseWarp(InputArray _img1, OutputArray img2) const
{ {
Mat img1 = _img1.getMat();
// Rows and columns in destination // Rows and columns in destination
Mat dest_r, dest_c; Mat dest_r, dest_c;
dest_r.create(img1.size(), CV_32FC1); dest_r.create(img1.size(), CV_32FC1);
...@@ -91,10 +94,10 @@ Ptr<Map> MapShift::inverseMap(void) const ...@@ -91,10 +94,10 @@ Ptr<Map> MapShift::inverseMap(void) const
} }
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
void MapShift::compose(const Map& map) void MapShift::compose(cv::Ptr<Map> map)
{ {
// Composition of transformations T and T' is (T o T') = b + b' // Composition of transformations T and T' is (T o T') = b + b'
const MapShift& mapShift = static_cast<const MapShift&>(map); const MapShift& mapShift = static_cast<const MapShift&>(*map);
shift_ += mapShift.getShift(); shift_ += mapShift.getShift();
} }
......
...@@ -59,11 +59,13 @@ using namespace std; ...@@ -59,11 +59,13 @@ using namespace std;
using namespace cv; using namespace cv;
using namespace cv::reg; using namespace cv::reg;
#define REG_DEBUG_OUTPUT 0
class RegTest : public testing::Test class RegTest : public testing::Test
{ {
public: public:
void loadImage(); void loadImage(int dstDataType = CV_32FC3);
void testShift(); void testShift();
void testEuclidean(); void testEuclidean();
...@@ -84,20 +86,20 @@ void RegTest::testShift() ...@@ -84,20 +86,20 @@ void RegTest::testShift()
mapTest.warp(img1, img2); mapTest.warp(img1, img2);
// Register // Register
MapperGradShift mapper; Ptr<Mapper> mapper = makePtr<MapperGradShift>();
MapperPyramid mappPyr(mapper); MapperPyramid mappPyr(mapper);
Ptr<Map> mapPtr; Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
mappPyr.calculate(img1, img2, mapPtr);
// Print result // Print result
MapShift* mapShift = dynamic_cast<MapShift*>(mapPtr.get()); Ptr<MapShift> mapShift = MapTypeCaster::toShift(mapPtr);
#if REG_DEBUG_OUTPUT
cout << endl << "--- Testing shift mapper ---" << endl; cout << endl << "--- Testing shift mapper ---" << endl;
cout << Mat(shift) << endl; cout << Mat(shift) << endl;
cout << Mat(mapShift->getShift()) << endl; cout << Mat(mapShift->getShift()) << endl;
#endif
// Check accuracy // Check accuracy
Ptr<Map> mapInv(mapShift->inverseMap()); Ptr<Map> mapInv(mapShift->inverseMap());
mapTest.compose(*mapInv.get()); mapTest.compose(mapInv);
double shNorm = norm(mapTest.getShift()); double shNorm = norm(mapTest.getShift());
EXPECT_LE(shNorm, 0.1); EXPECT_LE(shNorm, 0.1);
} }
...@@ -116,22 +118,22 @@ void RegTest::testEuclidean() ...@@ -116,22 +118,22 @@ void RegTest::testEuclidean()
mapTest.warp(img1, img2); mapTest.warp(img1, img2);
// Register // Register
MapperGradEuclid mapper; Ptr<Mapper> mapper = makePtr<MapperGradEuclid>();
MapperPyramid mappPyr(mapper); MapperPyramid mappPyr(mapper);
Ptr<Map> mapPtr; Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
mappPyr.calculate(img1, img2, mapPtr);
// Print result // Print result
MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get()); Ptr<MapAffine> mapAff = MapTypeCaster::toAffine(mapPtr);
#if REG_DEBUG_OUTPUT
cout << endl << "--- Testing Euclidean mapper ---" << endl; cout << endl << "--- Testing Euclidean mapper ---" << endl;
cout << Mat(linTr) << endl; cout << Mat(linTr) << endl;
cout << Mat(shift) << endl; cout << Mat(shift) << endl;
cout << Mat(mapAff->getLinTr()) << endl; cout << Mat(mapAff->getLinTr()) << endl;
cout << Mat(mapAff->getShift()) << endl; cout << Mat(mapAff->getShift()) << endl;
#endif
// Check accuracy // Check accuracy
Ptr<Map> mapInv(mapAff->inverseMap()); Ptr<Map> mapInv(mapAff->inverseMap());
mapTest.compose(*mapInv.get()); mapTest.compose(mapInv);
double shNorm = norm(mapTest.getShift()); double shNorm = norm(mapTest.getShift());
EXPECT_LE(shNorm, 0.1); EXPECT_LE(shNorm, 0.1);
double linTrNorm = norm(mapTest.getLinTr()); double linTrNorm = norm(mapTest.getLinTr());
...@@ -154,22 +156,23 @@ void RegTest::testSimilarity() ...@@ -154,22 +156,23 @@ void RegTest::testSimilarity()
mapTest.warp(img1, img2); mapTest.warp(img1, img2);
// Register // Register
MapperGradSimilar mapper; Ptr<Mapper> mapper = makePtr<MapperGradSimilar>();
MapperPyramid mappPyr(mapper); MapperPyramid mappPyr(mapper);
Ptr<Map> mapPtr; Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
mappPyr.calculate(img1, img2, mapPtr);
// Print result // Print result
MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get()); Ptr<MapAffine> mapAff = MapTypeCaster::toAffine(mapPtr);
#if REG_DEBUG_OUTPUT
cout << endl << "--- Testing similarity mapper ---" << endl; cout << endl << "--- Testing similarity mapper ---" << endl;
cout << Mat(linTr) << endl; cout << Mat(linTr) << endl;
cout << Mat(shift) << endl; cout << Mat(shift) << endl;
cout << Mat(mapAff->getLinTr()) << endl; cout << Mat(mapAff->getLinTr()) << endl;
cout << Mat(mapAff->getShift()) << endl; cout << Mat(mapAff->getShift()) << endl;
#endif
// Check accuracy // Check accuracy
Ptr<Map> mapInv(mapAff->inverseMap()); Ptr<Map> mapInv(mapAff->inverseMap());
mapTest.compose(*mapInv.get()); mapTest.compose(mapInv);
double shNorm = norm(mapTest.getShift()); double shNorm = norm(mapTest.getShift());
EXPECT_LE(shNorm, 0.1); EXPECT_LE(shNorm, 0.1);
double linTrNorm = norm(mapTest.getLinTr()); double linTrNorm = norm(mapTest.getLinTr());
...@@ -188,22 +191,23 @@ void RegTest::testAffine() ...@@ -188,22 +191,23 @@ void RegTest::testAffine()
mapTest.warp(img1, img2); mapTest.warp(img1, img2);
// Register // Register
MapperGradAffine mapper; Ptr<Mapper> mapper = makePtr<MapperGradAffine>();
MapperPyramid mappPyr(mapper); MapperPyramid mappPyr(mapper);
Ptr<Map> mapPtr; Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
mappPyr.calculate(img1, img2, mapPtr);
// Print result // Print result
MapAffine* mapAff = dynamic_cast<MapAffine*>(mapPtr.get()); Ptr<MapAffine> mapAff = MapTypeCaster::toAffine(mapPtr);
#if REG_DEBUG_OUTPUT
cout << endl << "--- Testing affine mapper ---" << endl; cout << endl << "--- Testing affine mapper ---" << endl;
cout << Mat(linTr) << endl; cout << Mat(linTr) << endl;
cout << Mat(shift) << endl; cout << Mat(shift) << endl;
cout << Mat(mapAff->getLinTr()) << endl; cout << Mat(mapAff->getLinTr()) << endl;
cout << Mat(mapAff->getShift()) << endl; cout << Mat(mapAff->getShift()) << endl;
#endif
// Check accuracy // Check accuracy
Ptr<Map> mapInv(mapAff->inverseMap()); Ptr<Map> mapInv(mapAff->inverseMap());
mapTest.compose(*mapInv.get()); mapTest.compose(mapInv);
double shNorm = norm(mapTest.getShift()); double shNorm = norm(mapTest.getShift());
EXPECT_LE(shNorm, 0.1); EXPECT_LE(shNorm, 0.1);
double linTrNorm = norm(mapTest.getLinTr()); double linTrNorm = norm(mapTest.getLinTr());
...@@ -222,34 +226,34 @@ void RegTest::testProjective() ...@@ -222,34 +226,34 @@ void RegTest::testProjective()
mapTest.warp(img1, img2); mapTest.warp(img1, img2);
// Register // Register
MapperGradProj mapper; Ptr<Mapper> mapper = makePtr<MapperGradProj>();
MapperPyramid mappPyr(mapper); MapperPyramid mappPyr(mapper);
Ptr<Map> mapPtr; Ptr<Map> mapPtr = mappPyr.calculate(img1, img2);
mappPyr.calculate(img1, img2, mapPtr);
// Print result // Print result
MapProjec* mapProj = dynamic_cast<MapProjec*>(mapPtr.get()); Ptr<MapProjec> mapProj = MapTypeCaster::toProjec(mapPtr);
mapProj->normalize(); mapProj->normalize();
#if REG_DEBUG_OUTPUT
cout << endl << "--- Testing projective transformation mapper ---" << endl; cout << endl << "--- Testing projective transformation mapper ---" << endl;
cout << Mat(projTr) << endl; cout << Mat(projTr) << endl;
cout << Mat(mapProj->getProjTr()) << endl; cout << Mat(mapProj->getProjTr()) << endl;
#endif
// Check accuracy // Check accuracy
Ptr<Map> mapInv(mapProj->inverseMap()); Ptr<Map> mapInv(mapProj->inverseMap());
mapTest.compose(*mapInv.get()); mapTest.compose(mapInv);
double projNorm = norm(mapTest.getProjTr()); double projNorm = norm(mapTest.getProjTr());
EXPECT_LE(projNorm, sqrt(3.) + 0.01); EXPECT_LE(projNorm, sqrt(3.) + 0.01);
EXPECT_GE(projNorm, sqrt(3.) - 0.01); EXPECT_GE(projNorm, sqrt(3.) - 0.01);
} }
void RegTest::loadImage() void RegTest::loadImage(int dstDataType)
{ {
const string imageName = cvtest::TS::ptr()->get_data_path() + "reg/home.png"; const string imageName = cvtest::TS::ptr()->get_data_path() + "reg/home.png";
img1 = imread(imageName, -1); img1 = imread(imageName, -1);
ASSERT_TRUE(img1.data != 0); ASSERT_TRUE(!img1.empty());
// Convert to double, 3 channels img1.convertTo(img1, dstDataType);
img1.convertTo(img1, CV_64FC3);
} }
...@@ -282,3 +286,15 @@ TEST_F(RegTest, projective) ...@@ -282,3 +286,15 @@ TEST_F(RegTest, projective)
loadImage(); loadImage();
testProjective(); testProjective();
} }
TEST_F(RegTest, projective_dt64fc3)
{
loadImage(CV_64FC3);
testProjective();
}
TEST_F(RegTest, projective_dt64fc1)
{
loadImage(CV_64FC1);
testProjective();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment