From 6e2507c197e69ae25023fdf24d81c591cfaba827 Mon Sep 17 00:00:00 2001
From: Ivan Korolev <no@email>
Date: Wed, 14 Mar 2012 12:59:23 +0000
Subject: [PATCH] Added some new warpers.

---
 .../opencv2/stitching/detail/warpers.hpp      | 141 ++++++++
 .../opencv2/stitching/detail/warpers_inl.hpp  | 327 ++++++++++++++++++
 .../include/opencv2/stitching/warpers.hpp     |  69 ++++
 samples/cpp/stitching_detailed.cpp            |  14 +-
 4 files changed, 550 insertions(+), 1 deletion(-)

diff --git a/modules/stitching/include/opencv2/stitching/detail/warpers.hpp b/modules/stitching/include/opencv2/stitching/detail/warpers.hpp
index 812d7d0dc6..091b4fd83f 100644
--- a/modules/stitching/include/opencv2/stitching/detail/warpers.hpp
+++ b/modules/stitching/include/opencv2/stitching/detail/warpers.hpp
@@ -185,6 +185,147 @@ protected:
 };
 
 
+struct CV_EXPORTS FisheyeProjector : ProjectorBase
+{
+    void mapForward(float x, float y, float &u, float &v);
+    void mapBackward(float u, float v, float &x, float &y);
+};
+
+
+class CV_EXPORTS FisheyeWarper : public RotationWarperBase<FisheyeProjector>
+{
+public:
+    FisheyeWarper(float scale) { projector_.scale = scale; }
+};
+
+
+struct CV_EXPORTS StereographicProjector : ProjectorBase
+{
+    void mapForward(float x, float y, float &u, float &v);
+    void mapBackward(float u, float v, float &x, float &y);
+};
+
+
+class CV_EXPORTS StereographicWarper : public RotationWarperBase<StereographicProjector>
+{
+public:
+    StereographicWarper(float scale) { projector_.scale = scale; }
+};
+
+
+struct CV_EXPORTS CompressedRectilinearProjector : ProjectorBase
+{
+	float a, b;
+
+    void mapForward(float x, float y, float &u, float &v);
+    void mapBackward(float u, float v, float &x, float &y);
+};
+
+
+class CV_EXPORTS CompressedRectilinearWarper : public RotationWarperBase<CompressedRectilinearProjector>
+{
+public:
+   CompressedRectilinearWarper(float scale, float A = 1, float B = 1) 
+   { 
+	   projector_.a = A;
+	   projector_.b = B;
+	   projector_.scale = scale; 
+   }
+};
+
+
+struct CV_EXPORTS CompressedRectilinearPortraitProjector : ProjectorBase
+{
+	float a, b;
+
+    void mapForward(float x, float y, float &u, float &v);
+    void mapBackward(float u, float v, float &x, float &y);
+};
+
+
+class CV_EXPORTS CompressedRectilinearPortraitWarper : public RotationWarperBase<CompressedRectilinearPortraitProjector>
+{
+public:
+   CompressedRectilinearPortraitWarper(float scale, float A = 1, float B = 1) 
+   { 
+	   projector_.a = A;
+	   projector_.b = B;
+	   projector_.scale = scale; 
+   }
+};
+
+
+struct CV_EXPORTS PaniniProjector : ProjectorBase
+{
+	float a, b;
+
+    void mapForward(float x, float y, float &u, float &v);
+    void mapBackward(float u, float v, float &x, float &y);
+};
+
+
+class CV_EXPORTS PaniniWarper : public RotationWarperBase<PaniniProjector>
+{
+public:
+   PaniniWarper(float scale, float A = 1, float B = 1) 
+   { 
+	   projector_.a = A;
+	   projector_.b = B;
+	   projector_.scale = scale; 
+   }
+};
+
+
+struct CV_EXPORTS PaniniPortraitProjector : ProjectorBase
+{
+	float a, b;
+
+    void mapForward(float x, float y, float &u, float &v);
+    void mapBackward(float u, float v, float &x, float &y);
+};
+
+
+class CV_EXPORTS PaniniPortraitWarper : public RotationWarperBase<PaniniPortraitProjector>
+{
+public:
+   PaniniPortraitWarper(float scale, float A = 1, float B = 1) 
+   { 
+	   projector_.a = A;
+	   projector_.b = B;
+	   projector_.scale = scale; 
+   }
+
+};
+
+
+struct CV_EXPORTS MercatorProjector : ProjectorBase
+{
+    void mapForward(float x, float y, float &u, float &v);
+    void mapBackward(float u, float v, float &x, float &y);
+};
+
+
+class CV_EXPORTS MercatorWarper : public RotationWarperBase<MercatorProjector>
+{
+public:
+    MercatorWarper(float scale) { projector_.scale = scale; }
+};
+
+
+struct CV_EXPORTS TransverseMercatorProjector : ProjectorBase
+{
+    void mapForward(float x, float y, float &u, float &v);
+    void mapBackward(float u, float v, float &x, float &y);
+};
+
+
+class CV_EXPORTS TransverseMercatorWarper : public RotationWarperBase<TransverseMercatorProjector>
+{
+public:
+    TransverseMercatorWarper(float scale) { projector_.scale = scale; }
+};
+
+
 #ifdef HAVE_OPENCV_GPU
 class CV_EXPORTS PlaneWarperGpu : public PlaneWarper
 {
diff --git a/modules/stitching/include/opencv2/stitching/detail/warpers_inl.hpp b/modules/stitching/include/opencv2/stitching/detail/warpers_inl.hpp
index 78eb75625e..ec4af537a2 100644
--- a/modules/stitching/include/opencv2/stitching/detail/warpers_inl.hpp
+++ b/modules/stitching/include/opencv2/stitching/detail/warpers_inl.hpp
@@ -298,6 +298,333 @@ void CylindricalProjector::mapBackward(float u, float v, float &x, float &y)
     else x = y = -1;
 }
 
+inline
+void FisheyeProjector::mapForward(float x, float y, float &u, float &v)
+{
+	float x_ = r_kinv[0] * x + r_kinv[1] * y + r_kinv[2];
+    float y_ = r_kinv[3] * x + r_kinv[4] * y + r_kinv[5];
+    float z_ = r_kinv[6] * x + r_kinv[7] * y + r_kinv[8];
+
+	float u_ = atan2f(x_, z_);
+    float v_ = CV_PI - acosf(y_ / sqrtf(x_ * x_ + y_ * y_ + z_ * z_));
+
+	u = scale * v_ * cosf(u_);
+	v = scale * v_ * sinf(u_);
+}
+
+inline
+void FisheyeProjector::mapBackward(float u, float v, float &x, float &y)
+{
+	u /= scale;
+    v /= scale;
+
+	float u_ = atan2f(v, u);
+	float v_ = sqrtf(u*u + v*v);
+
+	float sinv = sinf(CV_PI - v_);
+    float x_ = sinv * sinf(u_);
+    float y_ = cosf(CV_PI - v_);
+    float z_ = sinv * cosf(u_);
+
+    float z;
+    x = k_rinv[0] * x_ + k_rinv[1] * y_ + k_rinv[2] * z_;
+    y = k_rinv[3] * x_ + k_rinv[4] * y_ + k_rinv[5] * z_;
+    z = k_rinv[6] * x_ + k_rinv[7] * y_ + k_rinv[8] * z_;
+
+	if (z > 0) { x /= z; y /= z; }
+    else x = y = -1;
+}
+
+inline
+void StereographicProjector::mapForward(float x, float y, float &u, float &v)
+{
+	float x_ = r_kinv[0] * x + r_kinv[1] * y + r_kinv[2];
+    float y_ = r_kinv[3] * x + r_kinv[4] * y + r_kinv[5];
+    float z_ = r_kinv[6] * x + r_kinv[7] * y + r_kinv[8];
+
+	float u_ = atan2f(x_, z_);
+    float v_ = CV_PI - acosf(y_ / sqrtf(x_ * x_ + y_ * y_ + z_ * z_));
+
+	float r = sinf(v_) / (1 - cosf(v_));
+	
+	u = scale * r * cos(u_);
+	v = scale * r * sin(u_);
+}
+
+inline
+void StereographicProjector::mapBackward(float u, float v, float &x, float &y)
+{
+	u /= scale;
+    v /= scale;
+
+	float u_ = atan2f(v, u);
+	float r = sqrtf(u*u + v*v);
+	float v_ = 2 * atanf(1.0 / r);
+
+	float sinv = sinf(CV_PI - v_);
+    float x_ = sinv * sinf(u_);
+    float y_ = cosf(CV_PI - v_);
+    float z_ = sinv * cosf(u_);
+
+    float z;
+    x = k_rinv[0] * x_ + k_rinv[1] * y_ + k_rinv[2] * z_;
+    y = k_rinv[3] * x_ + k_rinv[4] * y_ + k_rinv[5] * z_;
+    z = k_rinv[6] * x_ + k_rinv[7] * y_ + k_rinv[8] * z_;
+
+	if (z > 0) { x /= z; y /= z; }
+    else x = y = -1;
+}
+
+inline
+void CompressedRectilinearProjector::mapForward(float x, float y, float &u, float &v)
+{    
+	float x_ = r_kinv[0] * x + r_kinv[1] * y + r_kinv[2];
+    float y_ = r_kinv[3] * x + r_kinv[4] * y + r_kinv[5];
+    float z_ = r_kinv[6] * x + r_kinv[7] * y + r_kinv[8];
+
+    float u_ = atan2f(x_, z_);
+    float v_ = asinf(y_ / sqrtf(x_ * x_ + y_ * y_ + z_ * z_));
+
+	u = scale * a * tanf(u_ / a);
+	v = scale * b * tanf(v_) / cosf(u_);
+}
+
+inline
+void CompressedRectilinearProjector::mapBackward(float u, float v, float &x, float &y)
+{
+	u /= scale;
+    v /= scale;
+
+	float aatg = a * atanf(u / a);
+	float u_ = aatg;
+	float v_ = atanf(v * cosf(aatg) / b);
+
+    float cosv = cosf(v_);
+    float x_ = cosv * sinf(u_);
+    float y_ = sinf(v_);
+    float z_ = cosv * cosf(u_);
+
+    float z;
+    x = k_rinv[0] * x_ + k_rinv[1] * y_ + k_rinv[2] * z_;
+    y = k_rinv[3] * x_ + k_rinv[4] * y_ + k_rinv[5] * z_;
+    z = k_rinv[6] * x_ + k_rinv[7] * y_ + k_rinv[8] * z_;
+
+    if (z > 0) { x /= z; y /= z; }
+    else x = y = -1;
+}
+
+inline
+void CompressedRectilinearPortraitProjector::mapForward(float x, float y, float &u, float &v)
+{    
+	float y_ = r_kinv[0] * x + r_kinv[1] * y + r_kinv[2];
+    float x_ = r_kinv[3] * x + r_kinv[4] * y + r_kinv[5];
+    float z_ = r_kinv[6] * x + r_kinv[7] * y + r_kinv[8];
+
+    float u_ = atan2f(x_, z_);
+    float v_ = asinf(y_ / sqrtf(x_ * x_ + y_ * y_ + z_ * z_));
+
+	u = - scale * a * tanf(u_ / a);
+	v = scale * b * tanf(v_) / cosf(u_);
+}
+
+inline
+void CompressedRectilinearPortraitProjector::mapBackward(float u, float v, float &x, float &y)
+{
+	u /= - scale;
+    v /= scale;
+
+	float aatg = a * atanf(u / a);
+	float u_ = aatg;
+	float v_ = atanf(v * cosf( aatg ) / b);
+
+    float cosv = cosf(v_);
+    float y_ = cosv * sinf(u_);
+    float x_ = sinf(v_);
+    float z_ = cosv * cosf(u_);
+
+    float z;
+    x = k_rinv[0] * x_ + k_rinv[1] * y_ + k_rinv[2] * z_;
+    y = k_rinv[3] * x_ + k_rinv[4] * y_ + k_rinv[5] * z_;
+    z = k_rinv[6] * x_ + k_rinv[7] * y_ + k_rinv[8] * z_;
+
+    if (z > 0) { x /= z; y /= z; }
+    else x = y = -1;
+}
+
+inline
+void PaniniProjector::mapForward(float x, float y, float &u, float &v)
+{    
+	float x_ = r_kinv[0] * x + r_kinv[1] * y + r_kinv[2];
+    float y_ = r_kinv[3] * x + r_kinv[4] * y + r_kinv[5];
+    float z_ = r_kinv[6] * x + r_kinv[7] * y + r_kinv[8];
+
+    float u_ = atan2f(x_, z_);
+    float v_ = asinf(y_ / sqrtf(x_ * x_ + y_ * y_ + z_ * z_));
+	
+	float tg = a * tanf(u_ / a);
+	u = scale * tg;
+	
+	float sinu = sinf(u_);
+	if ( fabs(sinu) < 1E-7 )
+		v = scale * b * tanf(v_);
+	else
+		v = scale * b * tg * tanf(v_) / sinu;
+}
+
+inline
+void PaniniProjector::mapBackward(float u, float v, float &x, float &y)
+{
+	u /= scale;
+    v /= scale;
+
+	float lamda = a * atanf(u / a);
+	float u_ = lamda;
+	
+	float v_;
+	if ( fabs(lamda) > 1E-7)
+		v_ = atanf(v * sinf(lamda) / (b * a * tanf(lamda / a)));
+	else 
+		v_ = atanf(v / b);
+
+    float cosv = cosf(v_);
+    float x_ = cosv * sinf(u_);
+    float y_ = sinf(v_);
+    float z_ = cosv * cosf(u_);
+
+    float z;
+    x = k_rinv[0] * x_ + k_rinv[1] * y_ + k_rinv[2] * z_;
+    y = k_rinv[3] * x_ + k_rinv[4] * y_ + k_rinv[5] * z_;
+    z = k_rinv[6] * x_ + k_rinv[7] * y_ + k_rinv[8] * z_;
+
+    if (z > 0) { x /= z; y /= z; }
+    else x = y = -1;
+}
+
+inline
+void PaniniPortraitProjector::mapForward(float x, float y, float &u, float &v)
+{    
+	float y_ = r_kinv[0] * x + r_kinv[1] * y + r_kinv[2];
+    float x_ = r_kinv[3] * x + r_kinv[4] * y + r_kinv[5];
+    float z_ = r_kinv[6] * x + r_kinv[7] * y + r_kinv[8];
+
+    float u_ = atan2f(x_, z_);
+    float v_ = asinf(y_ / sqrtf(x_ * x_ + y_ * y_ + z_ * z_));
+	
+	float tg = a * tanf(u_ / a);
+	u = - scale * tg;
+	
+	float sinu = sinf( u_ );
+	if ( fabs(sinu) < 1E-7 )
+		v = scale * b * tanf(v_);
+	else
+		v = scale * b * tg * tanf(v_) / sinu;
+}
+
+inline
+void PaniniPortraitProjector::mapBackward(float u, float v, float &x, float &y)
+{
+	u /= - scale;
+    v /= scale;
+
+	float lamda = a * atanf(u / a);
+	float u_ = lamda;
+	
+	float v_;
+	if ( fabs(lamda) > 1E-7)
+		v_ = atanf(v * sinf(lamda) / (b * a * tanf(lamda/a)));
+	else 
+		v_ = atanf(v / b);
+
+    float cosv = cosf(v_);
+    float y_ = cosv * sinf(u_);
+    float x_ = sinf(v_);
+    float z_ = cosv * cosf(u_);
+
+    float z;
+    x = k_rinv[0] * x_ + k_rinv[1] * y_ + k_rinv[2] * z_;
+    y = k_rinv[3] * x_ + k_rinv[4] * y_ + k_rinv[5] * z_;
+    z = k_rinv[6] * x_ + k_rinv[7] * y_ + k_rinv[8] * z_;
+
+    if (z > 0) { x /= z; y /= z; }
+    else x = y = -1;
+}
+
+inline
+void MercatorProjector::mapForward(float x, float y, float &u, float &v)
+{    
+	float x_ = r_kinv[0] * x + r_kinv[1] * y + r_kinv[2];
+    float y_ = r_kinv[3] * x + r_kinv[4] * y + r_kinv[5];
+    float z_ = r_kinv[6] * x + r_kinv[7] * y + r_kinv[8];
+
+    float u_ = atan2f(x_, z_);
+    float v_ = asinf(y_ / sqrtf(x_ * x_ + y_ * y_ + z_ * z_));
+	
+	u = scale * u_;
+	v = scale * logf( tanf( CV_PI/4 + v_/2 ) );
+}
+
+inline
+void MercatorProjector::mapBackward(float u, float v, float &x, float &y)
+{
+	u /= scale;
+    v /= scale;
+
+	float v_ = atanf( sinhf(v) );
+	float u_ = u;
+
+    float cosv = cosf(v_);
+    float x_ = cosv * sinf(u_);
+    float y_ = sinf(v_);
+    float z_ = cosv * cosf(u_);
+
+    float z;
+    x = k_rinv[0] * x_ + k_rinv[1] * y_ + k_rinv[2] * z_;
+    y = k_rinv[3] * x_ + k_rinv[4] * y_ + k_rinv[5] * z_;
+    z = k_rinv[6] * x_ + k_rinv[7] * y_ + k_rinv[8] * z_;
+
+    if (z > 0) { x /= z; y /= z; }
+    else x = y = -1;
+}
+
+inline
+void TransverseMercatorProjector::mapForward(float x, float y, float &u, float &v)
+{    
+	float x_ = r_kinv[0] * x + r_kinv[1] * y + r_kinv[2];
+    float y_ = r_kinv[3] * x + r_kinv[4] * y + r_kinv[5];
+    float z_ = r_kinv[6] * x + r_kinv[7] * y + r_kinv[8];
+
+    float u_ = atan2f(x_, z_);
+    float v_ = asinf(y_ / sqrtf(x_ * x_ + y_ * y_ + z_ * z_));
+	
+	float B = cosf(v_) * sinf(u_);
+	
+	u = scale / 2 * logf( (1+B) / (1-B) );
+	v = scale * atan2f(tanf(v_), cosf(u_));
+}
+
+inline
+void TransverseMercatorProjector::mapBackward(float u, float v, float &x, float &y)
+{
+	u /= scale;
+    v /= scale;
+
+	float v_ = asinf( sinf(v) / coshf(u) );
+	float u_ = atan2f( sinhf(u), cos(v) );
+
+    float cosv = cosf(v_);
+    float x_ = cosv * sinf(u_);
+    float y_ = sinf(v_);
+    float z_ = cosv * cosf(u_);
+
+    float z;
+    x = k_rinv[0] * x_ + k_rinv[1] * y_ + k_rinv[2] * z_;
+    y = k_rinv[3] * x_ + k_rinv[4] * y_ + k_rinv[5] * z_;
+    z = k_rinv[6] * x_ + k_rinv[7] * y_ + k_rinv[8] * z_;
+
+    if (z > 0) { x /= z; y /= z; }
+    else x = y = -1;
+}
+
 inline
 void SphericalPortraitProjector::mapForward(float x, float y, float &u0, float &v0)
 {    
diff --git a/modules/stitching/include/opencv2/stitching/warpers.hpp b/modules/stitching/include/opencv2/stitching/warpers.hpp
index a321c3987f..4c5cd59e40 100644
--- a/modules/stitching/include/opencv2/stitching/warpers.hpp
+++ b/modules/stitching/include/opencv2/stitching/warpers.hpp
@@ -75,6 +75,75 @@ public:
     Ptr<detail::RotationWarper> create(float scale) const { return new detail::SphericalWarper(scale); }
 };
 
+class FisheyeWarper : public WarperCreator
+{
+public:
+    Ptr<detail::RotationWarper> create(float scale) const { return new detail::FisheyeWarper(scale); }
+};
+
+class StereographicWarper: public WarperCreator
+{
+public:
+    Ptr<detail::RotationWarper> create(float scale) const { return new detail::StereographicWarper(scale); }
+};
+
+class CompressedRectilinearWarper: public WarperCreator
+{
+	float a, b;
+public:
+	CompressedRectilinearWarper(float A = 1, float B = 1)
+	{
+		a = A; b = B;
+	}
+    Ptr<detail::RotationWarper> create(float scale) const { return new detail::CompressedRectilinearWarper(scale, a, b); }
+};
+
+class CompressedRectilinearPortraitWarper: public WarperCreator
+{
+	float a, b;
+public:
+	CompressedRectilinearPortraitWarper(float A = 1, float B = 1)
+	{
+		a = A; b = B;
+	}
+    Ptr<detail::RotationWarper> create(float scale) const { return new detail::CompressedRectilinearPortraitWarper(scale, a, b); }
+};
+
+class PaniniWarper: public WarperCreator
+{
+	float a, b;
+public:
+	PaniniWarper(float A = 1, float B = 1)
+	{
+		a = A; b = B;
+	}
+    Ptr<detail::RotationWarper> create(float scale) const { return new detail::PaniniWarper(scale, a, b); }
+};
+
+class PaniniPortraitWarper: public WarperCreator
+{
+	float a, b;
+public:
+	PaniniPortraitWarper(float A = 1, float B = 1)
+	{
+		a = A; b = B;
+	}
+    Ptr<detail::RotationWarper> create(float scale) const { return new detail::PaniniPortraitWarper(scale, a, b); }
+};
+
+class MercatorWarper: public WarperCreator
+{
+public:
+    Ptr<detail::RotationWarper> create(float scale) const { return new detail::MercatorWarper(scale); }
+};
+
+class TransverseMercatorWarper: public WarperCreator
+{
+public:
+    Ptr<detail::RotationWarper> create(float scale) const { return new detail::TransverseMercatorWarper(scale); }
+};
+
+
 
 #ifdef HAVE_OPENCV_GPU
 class PlaneWarperGpu: public WarperCreator
diff --git a/samples/cpp/stitching_detailed.cpp b/samples/cpp/stitching_detailed.cpp
index c2f943942c..609cd48bad 100644
--- a/samples/cpp/stitching_detailed.cpp
+++ b/samples/cpp/stitching_detailed.cpp
@@ -98,7 +98,7 @@ void printUsage()
         "      Labels description: Nm is number of matches, Ni is number of inliers,\n"
         "      C is confidence.\n"
         "\nCompositing Flags:\n"
-        "  --warp (plane|cylindrical|spherical)\n"
+        "  --warp (plane|cylindrical|spherical|fisheye|stereographic|compressedPlaneA2B1|compressedPlaneA1.5B1|compressedPlanePortraitA2B1|compressedPlanePortraitA1.5B1|paniniA2B1|paniniA1.5B1|paniniPortraitA2B1|paniniPortraitA1.5B1|mercator|transverseMercator)\n"
         "      Warp surface type. The default is 'spherical'.\n"
         "  --seam_megapix <float>\n"
         "      Resolution for seam estimation step. The default is 0.1 Mpx.\n"
@@ -544,6 +544,18 @@ int main(int argc, char* argv[])
         if (warp_type == "plane") warper_creator = new cv::PlaneWarper();
         else if (warp_type == "cylindrical") warper_creator = new cv::CylindricalWarper();
         else if (warp_type == "spherical") warper_creator = new cv::SphericalWarper();
+		else if (warp_type == "fisheye") warper_creator = new cv::FisheyeWarper();
+		else if (warp_type == "stereographic") warper_creator = new cv::StereographicWarper();
+		else if (warp_type == "compressedPlaneA2B1") warper_creator = new cv::CompressedRectilinearWarper(2, 1);
+		else if (warp_type == "compressedPlaneA1.5B1") warper_creator = new cv::CompressedRectilinearWarper(1.5, 1);
+		else if (warp_type == "compressedPlanePortraitA2B1") warper_creator = new cv::CompressedRectilinearPortraitWarper(2, 1);
+		else if (warp_type == "compressedPlanePortraitA1.5B1") warper_creator = new cv::CompressedRectilinearPortraitWarper(1.5, 1);
+		else if (warp_type == "paniniA2B1") warper_creator = new cv::PaniniWarper(2, 1);
+		else if (warp_type == "paniniA1.5B1") warper_creator = new cv::PaniniWarper(1.5, 1);
+		else if (warp_type == "paniniPortraitA2B1") warper_creator = new cv::PaniniPortraitWarper(2, 1);
+		else if (warp_type == "paniniPortraitA1.5B1") warper_creator = new cv::PaniniPortraitWarper(1.5, 1);
+		else if (warp_type == "mercator") warper_creator = new cv::MercatorWarper();
+		else if (warp_type == "transverseMercator") warper_creator = new cv::TransverseMercatorWarper();
     }
 
     if (warper_creator.empty())