diff --git a/modules/stitching/include/opencv2/stitching/detail/warpers.hpp b/modules/stitching/include/opencv2/stitching/detail/warpers.hpp index 706141140..4a9bafe64 100644 --- a/modules/stitching/include/opencv2/stitching/detail/warpers.hpp +++ b/modules/stitching/include/opencv2/stitching/detail/warpers.hpp @@ -304,6 +304,45 @@ private: }; #endif + +struct SphericalPortraitProjector : ProjectorBase +{ + void mapForward(float x, float y, float &u, float &v); + void mapBackward(float u, float v, float &x, float &y); +}; + + +// Projects image onto unit sphere with origin at (0, 0, 0). +// Poles are located NOT at (0, -1, 0) and (0, 1, 0) points, BUT at (1, 0, 0) and (-1, 0, 0) points. +class SphericalPortraitWarper : public RotationWarperBase +{ +public: + SphericalPortraitWarper(float scale) { projector_.scale = scale; } + +protected: + void detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br); +}; + +struct CylindricalPortraitProjector : ProjectorBase +{ + void mapForward(float x, float y, float &u, float &v); + void mapBackward(float u, float v, float &x, float &y); +}; + + +class CylindricalPortraitWarper : public RotationWarperBase +{ +public: + CylindricalPortraitWarper(float scale) { projector_.scale = scale; } + +protected: + void detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br) + { + RotationWarperBase::detectResultRoiByBorder(src_size, dst_tl, dst_br); + } +}; + + } // namespace detail } // namespace cv diff --git a/modules/stitching/include/opencv2/stitching/detail/warpers_inl.hpp b/modules/stitching/include/opencv2/stitching/detail/warpers_inl.hpp index e925c6310..d1ff56d03 100644 --- a/modules/stitching/include/opencv2/stitching/detail/warpers_inl.hpp +++ b/modules/stitching/include/opencv2/stitching/detail/warpers_inl.hpp @@ -298,6 +298,97 @@ void CylindricalProjector::mapBackward(float u, float v, float &x, float &y) else x = y = -1; } +inline +void SphericalPortraitProjector::mapForward(float x, float y, float &u0, float &v0) +{ + float x0_ = r_kinv[0] * x + r_kinv[1] * y + r_kinv[2]; + float y0_ = 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 x_ = y0_; + float y_ = x0_; + float u, v; + + u = scale * atan2f(x_, z_); + v = scale * (static_cast(CV_PI) - acosf(y_ / sqrtf(x_ * x_ + y_ * y_ + z_ * z_))); + + u0 = -u;//v; + v0 = v;//u; +} + + +inline +void SphericalPortraitProjector::mapBackward(float u0, float v0, float &x, float &y) +{ + float u, v; + u = -u0;//v0; + v = v0;//u0; + + u /= scale; + v /= scale; + + float sinv = sinf(static_cast(CV_PI) - v); + float x0_ = sinv * sinf(u); + float y0_ = cosf(static_cast(CV_PI) - v); + float z_ = sinv * cosf(u); + + float x_ = y0_; + float y_ = x0_; + + 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 CylindricalPortraitProjector::mapForward(float x, float y, float &u0, float &v0) +{ + float x0_ = r_kinv[0] * x + r_kinv[1] * y + r_kinv[2]; + float y0_ = 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 x_ = y0_; + float y_ = x0_; + float u, v; + + u = scale * atan2f(x_, z_); + v = scale * y_ / sqrtf(x_ * x_ + z_ * z_); + + u0 = -u;//v; + v0 = v;//u; +} + + +inline +void CylindricalPortraitProjector::mapBackward(float u0, float v0, float &x, float &y) +{ + float u, v; + u = -u0;//v0; + v = v0;//u0; + + u /= scale; + v /= scale; + + float x0_ = sinf(u); + float y0_ = v; + float z_ = cosf(u); + + float x_ = y0_; + float y_ = x0_; + + 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; +} + } // namespace detail } // namespace cv diff --git a/modules/stitching/src/warpers.cpp b/modules/stitching/src/warpers.cpp index 235656e4f..f3bb48083 100644 --- a/modules/stitching/src/warpers.cpp +++ b/modules/stitching/src/warpers.cpp @@ -296,5 +296,48 @@ Point CylindricalWarperGpu::warp(const gpu::GpuMat &src, const Mat &K, const Mat } #endif +void SphericalPortraitWarper::detectResultRoi(Size src_size, Point &dst_tl, Point &dst_br) +{ + detectResultRoiByBorder(src_size, dst_tl, dst_br); + + float tl_uf = static_cast(dst_tl.x); + float tl_vf = static_cast(dst_tl.y); + float br_uf = static_cast(dst_br.x); + float br_vf = static_cast(dst_br.y); + + float x = projector_.rinv[0]; + float y = projector_.rinv[3]; + float z = projector_.rinv[6]; + if (y > 0.f) + { + float x_ = (projector_.k[0] * x + projector_.k[1] * y) / z + projector_.k[2]; + float y_ = projector_.k[4] * y / z + projector_.k[5]; + if (x_ > 0.f && x_ < src_size.width && y_ > 0.f && y_ < src_size.height) + { + tl_uf = min(tl_uf, 0.f); tl_vf = min(tl_vf, static_cast(CV_PI * projector_.scale)); + br_uf = max(br_uf, 0.f); br_vf = max(br_vf, static_cast(CV_PI * projector_.scale)); + } + } + + x = projector_.rinv[0]; + y = -projector_.rinv[3]; + z = projector_.rinv[6]; + if (y > 0.f) + { + float x_ = (projector_.k[0] * x + projector_.k[1] * y) / z + projector_.k[2]; + float y_ = projector_.k[4] * y / z + projector_.k[5]; + if (x_ > 0.f && x_ < src_size.width && y_ > 0.f && y_ < src_size.height) + { + tl_uf = min(tl_uf, 0.f); tl_vf = min(tl_vf, static_cast(0)); + br_uf = max(br_uf, 0.f); br_vf = max(br_vf, static_cast(0)); + } + } + + dst_tl.x = static_cast(tl_uf); + dst_tl.y = static_cast(tl_vf); + dst_br.x = static_cast(br_uf); + dst_br.y = static_cast(br_vf); +} + } // namespace detail } // namespace cv