diff --git a/modules/imgproc/doc/pics/polar_remap_doc.png b/modules/imgproc/doc/pics/polar_remap_doc.png
index e3e4105bb8..b0b8431c51 100644
Binary files a/modules/imgproc/doc/pics/polar_remap_doc.png and b/modules/imgproc/doc/pics/polar_remap_doc.png differ
diff --git a/modules/imgproc/doc/pics/polar_remap_doc.svg b/modules/imgproc/doc/pics/polar_remap_doc.svg
index 544221569d..7d7a2f43b1 100644
--- a/modules/imgproc/doc/pics/polar_remap_doc.svg
+++ b/modules/imgproc/doc/pics/polar_remap_doc.svg
@@ -19,11 +19,199 @@
version="1.0"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
inkscape:export-ydpi="90"
- inkscape:version="0.91 r13725"
- width="1280"
- height="1000">
+ inkscape:version="0.92.1 r15371"
+ width="1279.0021"
+ height="1282.9999">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
@@ -119,8 +277,8 @@
inkscape:stockid="Arrow1Lend">
@@ -134,41 +292,11 @@
inkscape:stockid="Arrow1Lend">
-
-
-
-
-
-
@@ -257,8 +385,8 @@
inkscape:stockid="Arrow1Lend">
@@ -272,9 +400,9 @@
inkscape:isstock="true">
@@ -304,8 +432,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
@@ -412,8 +478,8 @@
inkscape:isstock="true">
@@ -427,8 +493,8 @@
inkscape:stockid="Arrow1Lend">
@@ -444,8 +510,8 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -472,27 +742,27 @@
guidetolerance="10"
pagecolor="#ffffff"
gridtolerance="10000"
- inkscape:zoom="0.881"
+ inkscape:zoom="0.62296106"
objecttolerance="10"
showgrid="true"
borderopacity="1.0"
inkscape:current-layer="layer1"
- inkscape:cx="640"
- inkscape:cy="454.59705"
+ inkscape:cx="311.69474"
+ inkscape:cy="489.42857"
showguides="true"
inkscape:guide-bbox="true"
inkscape:pageopacity="0.0"
inkscape:document-units="px"
inkscape:window-width="1920"
- inkscape:window-height="1058"
- inkscape:window-x="-8"
+ inkscape:window-height="1017"
+ inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:snap-smooth-nodes="true"
inkscape:snap-object-midpoints="true"
fit-margin-top="0"
- fit-margin-left="0"
- fit-margin-right="0"
+ fit-margin-left="10"
+ fit-margin-right="10"
fit-margin-bottom="0"
inkscape:snap-bbox="true"
inkscape:object-nodes="true"
@@ -506,12 +776,15 @@
inkscape:snap-intersection-paths="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
- inkscape:snap-global="true">
+ inkscape:snap-global="true"
+ inkscape:snap-text-baseline="false">
+ enabled="false"
+ originx="2.3367188e-005"
+ originy="283" />
+ height="723"
+ width="230" />
@@ -2734,7 +2044,7 @@ TkSuQmCC
height="100%" />
maxRadius
+ style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:center;text-anchor:middle;fill:#000000">maxRadius
angle°
magnitude
+ style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:serif;-inkscape-font-specification:'serif Italic';fill:#ff00ff">magnitude
dx
dy
centercenterC(xc , yc)
A(xA(xA , yA)
BOUNDING CIRCLE
+ style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:serif;-inkscape-font-specification:'serif Italic';stroke:#ffffff;stroke-opacity:1">BOUNDING CIRCLE
a) Source Image
+ y="-200.22424"
+ style="font-size:20px;line-height:1.25">a) Source Image
ρ: 0 .. Kx * maxRadius = src.cols
+ id="textPath8906">ρ: 0 .. dsize.cols = Kx * maxRadius
centercenterC(0,0)
+ style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:1.25;font-family:serif;-inkscape-font-specification:'serif Italic';fill:#ffffff;fill-opacity:1">C(0,0)
centercenterC(0,0)
+ style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:1.25;font-family:serif;-inkscape-font-specification:'serif Italic';fill:#000000;fill-opacity:1">C(0,0)
- ρA = Kx * magnitude
ϕA = Ky * angle°
A(ρA(ρA , ϕA)
if 2 * maxRadius > min(srcSize)CV_WARP_FILL_OUTLIERS
+ style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.5px;line-height:1.25;font-family:serif;-inkscape-font-specification:'serif Italic'">CV_WARP_FILL_OUTLIERS
M = src.cols / logKangle = dsize.height / 2PIKlog = dsize.width / loge(maxRadius)Ky = src.rows / 360.0
+ x="2081.5286"
+ y="784.16187"
+ style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.33333397px;line-height:1.25;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:start;text-anchor:start;fill:#000000;stroke:none"
+ id="tspan5743" />
Blue cross in the center
- if 2 * maxRadius > min(srcSize)CV_WARP_FILL_OUTLIERS
- Blue cross in the center
+ x="1168.9106"
+ y="1572.3779" />
c) linearPolar Result Image
+ x="1469.0718"
+ y="1592.7539"
+ style="font-size:20px;line-height:1.25">c) linearPolar() Deprecated
+ x="1814.2898"
+ y="972.29041" />
d) logPolar Result Image
-
-
+ x="1930.574"
+ y="992.42224"
+ style="font-size:20px;line-height:1.25">d) semiLog=true
-
ϕA = Ky * angle°
-
+ id="tspan25233">A = Kangle * angle
A(ρA(ρA , ϕA)
Kx = src.cols / maxRadiusKx = src.cols / maxRadiusKy = src.rows / 360.0
+ x="1264.3926"
+ y="1342.166"
+ style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:17.5px;line-height:1.25;font-family:serif;-inkscape-font-specification:'serif Italic';text-align:start;text-anchor:start"
+ id="tspan9683">Ky = src.rows / 2PI
ρ: 0 .. M * loge(maxRadius) = src.cols
+ style="font-style:normal;font-weight:normal;font-size:17.5px;line-height:0%;font-family:sans-serif;text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;display:inline;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ y="226.32253"
+ x="1967.1508"
+ id="text7021">ρ: 0..dsize.width = Klog * loge(maxRadius)
ϕ: 0 .. Ky * 360 = src.rows
+ id="textPath9479">ϕ: 0 .. dsize.height = Kangle * 2PI
ρA = M * loge(magnitude )
+ x="1921.4661"
+ y="399.7308">ρA = Klog*loge(magnitude )
+ inkscape:export-xdpi="96"
+ inkscape:export-ydpi="96">
+ style="display:inline;fill:#008080;fill-opacity:1;stroke:none;stroke-width:0.99999994;stroke-miterlimit:4;stroke-dasharray:1, 1;stroke-dashoffset:0;stroke-opacity:1"
+ inkscape:export-filename=".\polar_remap_src.png" />
270
+ sodipodi:role="line"
+ style="font-size:20.00708008px;line-height:1.25">270
240
+ sodipodi:role="line"
+ style="font-size:20.00708008px;line-height:1.25">240
210
+ sodipodi:role="line"
+ style="font-size:20.00708008px;line-height:1.25">210
180
+ sodipodi:role="line"
+ style="font-size:20.00708008px;line-height:1.25">180
150
+ sodipodi:role="line"
+ style="font-size:20.00708008px;line-height:1.25">150
120
+ sodipodi:role="line"
+ style="font-size:20.00708008px;line-height:1.25">120
90
+ sodipodi:role="line"
+ style="font-size:20.00708008px;line-height:1.25">90
60
+ sodipodi:role="line"
+ style="font-size:20.00708008px;line-height:1.25">60
30
+ sodipodi:role="line"
+ style="font-size:20.00708008px;line-height:1.25">30
300
+ sodipodi:role="line"
+ style="font-size:20.00708008px;line-height:1.25">330
330
+ sodipodi:role="line"
+ style="font-size:20.00708008px;line-height:1.25">300
0
+ sodipodi:role="line"
+ style="font-size:20.00708008px;line-height:1.25">0
-
Size: W:600 H:440 pxSize: W:600 H:440 pxCenter = x:240, y:220magnitude=100pxangle = 60degangle = 60degmaxRadius= 230px
+ style="font-size:17.5px;line-height:1.25;text-align:start;text-anchor:start">maxRadius= 230px
Kx = 600px / 230px = 2.609 => rho = 260.869pxKx = 600px / 230px = 2.609 => rho = 260.869pxKy = 440px / 360deg = 1.222 pix/deg = phi = 73.333pxM = 600px / ln(230px) = 110.33 pn/ln(px) => rho = 508.103px
b) Params References
+ y="-200.08264"
+ style="font-size:20px;line-height:1.25">b) Params References
+ OUTLIERS
+
+
+ ρA = Kx * magnitude
+
+
+ ρ: 0 .. dsize.width = Klin * maxRadius
+
+ centerC(0,0)
+
+
+ ϕA = Kphi * angle°
+ A(ρA , ϕA)
+ Blue crossin thecenter
+
+
+
+
+ ρA = Klin * magnitude
+ CV_WARP_FILL_OUTLIERS
+
+
+
+ ϕ: 0 .. dsize.height = Kangle * 2PI
+
+ c) semiLog=false
+ Kangle = dsize.height / 2PIKlin = dsize.width / maxRadius
+ Blue crossin thecenter
+ CV_WARP_FILL_OUTLIERS
+
+
@@ -3744,7 +3265,7 @@ TkSuQmCC
OpenCV
-
+
2016-08-08
diff --git a/modules/imgproc/include/opencv2/imgproc.hpp b/modules/imgproc/include/opencv2/imgproc.hpp
index b93a10c0d9..ab46838160 100644
--- a/modules/imgproc/include/opencv2/imgproc.hpp
+++ b/modules/imgproc/include/opencv2/imgproc.hpp
@@ -295,6 +295,15 @@ enum InterpolationFlags{
WARP_INVERSE_MAP = 16
};
+/** \brief Specify the polar mapping mode
+@sa warpPolar
+*/
+enum WarpPolarMode
+{
+ WARP_POLAR_LINEAR = 0, ///< Remaps an image to/from polar space.
+ WARP_POLAR_LOG = 256 ///< Remaps an image to/from semilog-polar space.
+};
+
enum InterpolationMasks {
INTER_BITS = 5,
INTER_BITS2 = INTER_BITS * 2,
@@ -2546,7 +2555,10 @@ An example using the cv::linearPolar and cv::logPolar operations
/** @brief Remaps an image to semilog-polar coordinates space.
-Transform the source image using the following transformation (See @ref polar_remaps_reference_image "Polar remaps reference image"):
+@deprecated This function produces same result as cv::warpPolar(src, dst, src.size(), center, maxRadius, flags+WARP_POLAR_LOG);
+
+@internal
+Transform the source image using the following transformation (See @ref polar_remaps_reference_image "Polar remaps reference image d)"):
\f[\begin{array}{l}
dst( \rho , \phi ) = src(x,y) \\
dst.size() \leftarrow src.size()
@@ -2556,13 +2568,13 @@ where
\f[\begin{array}{l}
I = (dx,dy) = (x - center.x,y - center.y) \\
\rho = M \cdot log_e(\texttt{magnitude} (I)) ,\\
- \phi = Ky \cdot \texttt{angle} (I)_{0..360 deg} \\
+ \phi = Kangle \cdot \texttt{angle} (I) \\
\end{array}\f]
and
\f[\begin{array}{l}
M = src.cols / log_e(maxRadius) \\
- Ky = src.rows / 360 \\
+ Kangle = src.rows / 2\Pi \\
\end{array}\f]
The function emulates the human "foveal" vision and can be used for fast scale and
@@ -2576,16 +2588,19 @@ rotation-invariant template matching, for object tracking and so forth.
@note
- The function can not operate in-place.
- To calculate magnitude and angle in degrees #cartToPolar is used internally thus angles are measured from 0 to 360 with accuracy about 0.3 degrees.
+
+@sa cv::linearPolar
+@endinternal
*/
CV_EXPORTS_W void logPolar( InputArray src, OutputArray dst,
Point2f center, double M, int flags );
/** @brief Remaps an image to polar coordinates space.
-@anchor polar_remaps_reference_image
-
+@deprecated This function produces same result as cv::warpPolar(src, dst, src.size(), center, maxRadius, flags)
-Transform the source image using the following transformation:
+@internal
+Transform the source image using the following transformation (See @ref polar_remaps_reference_image "Polar remaps reference image c)"):
\f[\begin{array}{l}
dst( \rho , \phi ) = src(x,y) \\
dst.size() \leftarrow src.size()
@@ -2594,14 +2609,14 @@ Transform the source image using the following transformation:
where
\f[\begin{array}{l}
I = (dx,dy) = (x - center.x,y - center.y) \\
- \rho = Kx \cdot \texttt{magnitude} (I) ,\\
- \phi = Ky \cdot \texttt{angle} (I)_{0..360 deg}
+ \rho = Kmag \cdot \texttt{magnitude} (I) ,\\
+ \phi = angle \cdot \texttt{angle} (I)
\end{array}\f]
and
\f[\begin{array}{l}
Kx = src.cols / maxRadius \\
- Ky = src.rows / 360
+ Ky = src.rows / 2\Pi
\end{array}\f]
@@ -2615,10 +2630,104 @@ and
- The function can not operate in-place.
- To calculate magnitude and angle in degrees #cartToPolar is used internally thus angles are measured from 0 to 360 with accuracy about 0.3 degrees.
+@sa cv::logPolar
+@endinternal
*/
CV_EXPORTS_W void linearPolar( InputArray src, OutputArray dst,
Point2f center, double maxRadius, int flags );
+
+/** \brief Remaps an image to polar or semilog-polar coordinates space
+
+@anchor polar_remaps_reference_image
+
+
+Transform the source image using the following transformation:
+\f[
+dst(\rho , \phi ) = src(x,y)
+\f]
+
+where
+\f[
+\begin{array}{l}
+\vec{I} = (x - center.x, \;y - center.y) \\
+\phi = Kangle \cdot \texttt{angle} (\vec{I}) \\
+\rho = \left\{\begin{matrix}
+Klin \cdot \texttt{magnitude} (\vec{I}) & default \\
+Klog \cdot log_e(\texttt{magnitude} (\vec{I})) & if \; semilog \\
+\end{matrix}\right.
+\end{array}
+\f]
+
+and
+\f[
+\begin{array}{l}
+Kangle = dsize.height / 2\Pi \\
+Klin = dsize.width / maxRadius \\
+Klog = dsize.width / log_e(maxRadius) \\
+\end{array}
+\f]
+
+
+\par Linear vs semilog mapping
+
+Polar mapping can be linear or semi-log. Add one of #WarpPolarMode to `flags` to specify the polar mapping mode.
+
+Linear is the default mode.
+
+The semilog mapping emulates the human "foveal" vision that permit very high acuity on the line of sight (central vision)
+in contrast to peripheral vision where acuity is minor.
+
+\par Option on `dsize`:
+
+- if both values in `dsize <=0 ` (default),
+the destination image will have (almost) same area of source bounding circle:
+\f[\begin{array}{l}
+dsize.area \leftarrow (maxRadius^2 \cdot \Pi) \\
+dsize.width = \texttt{cvRound}(maxRadius) \\
+dsize.height = \texttt{cvRound}(maxRadius \cdot \Pi) \\
+\end{array}\f]
+
+
+- if only `dsize.height <= 0`,
+the destination image area will be proportional to the bounding circle area but scaled by `Kx * Kx`:
+\f[\begin{array}{l}
+dsize.height = \texttt{cvRound}(dsize.width \cdot \Pi) \\
+\end{array}
+\f]
+
+- if both values in `dsize > 0 `,
+the destination image will have the given size therefore the area of the bounding circle will be scaled to `dsize`.
+
+
+\par Reverse mapping
+
+You can get reverse mapping adding #WARP_INVERSE_MAP to `flags`
+\snippet polar_transforms.cpp InverseMap
+
+In addiction, to calculate the original coordinate from a polar mapped coordinate \f$(rho, phi)->(x, y)\f$:
+\snippet polar_transforms.cpp InverseCoordinate
+
+@param src Source image.
+@param dst Destination image. It will have same type as src.
+@param dsize The destination image size (see description for valid options).
+@param center The transformation center.
+@param maxRadius The radius of the bounding circle to transform. It determines the inverse magnitude scale parameter too.
+@param flags A combination of interpolation methods, #InterpolationFlags + #WarpPolarMode.
+ - Add #WARP_POLAR_LINEAR to select linear polar mapping (default)
+ - Add #WARP_POLAR_LOG to select semilog polar mapping
+ - Add #WARP_INVERSE_MAP for reverse mapping.
+@note
+- The function can not operate in-place.
+- To calculate magnitude and angle in degrees #cartToPolar is used internally thus angles are measured from 0 to 360 with accuracy about 0.3 degrees.
+- This function uses #remap. Due to current implementation limitations the size of an input and output images should be less than 32767x32767.
+
+@sa cv::remap
+*/
+CV_EXPORTS_W void warpPolar(InputArray src, OutputArray dst, Size dsize,
+ Point2f center, double maxRadius, int flags);
+
+
//! @} imgproc_transform
//! @addtogroup imgproc_misc
diff --git a/modules/imgproc/include/opencv2/imgproc/imgproc_c.h b/modules/imgproc/include/opencv2/imgproc/imgproc_c.h
index fadb8820b7..78032b7626 100644
--- a/modules/imgproc/include/opencv2/imgproc/imgproc_c.h
+++ b/modules/imgproc/include/opencv2/imgproc/imgproc_c.h
@@ -260,14 +260,14 @@ CVAPI(void) cvConvertMaps( const CvArr* mapx, const CvArr* mapy,
CvArr* mapxy, CvArr* mapalpha );
/** @brief Performs forward or inverse log-polar image transform
-@see cv::logPolar
+@see cv::warpPolar
*/
CVAPI(void) cvLogPolar( const CvArr* src, CvArr* dst,
CvPoint2D32f center, double M,
int flags CV_DEFAULT(CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS));
/** Performs forward or inverse linear-polar image transform
-@see cv::linearPolar
+@see cv::warpPolar
*/
CVAPI(void) cvLinearPolar( const CvArr* src, CvArr* dst,
CvPoint2D32f center, double maxRadius,
diff --git a/modules/imgproc/perf/opencl/perf_imgwarp.cpp b/modules/imgproc/perf/opencl/perf_imgwarp.cpp
index 44fb84d1cc..d13b54bdce 100644
--- a/modules/imgproc/perf/opencl/perf_imgwarp.cpp
+++ b/modules/imgproc/perf/opencl/perf_imgwarp.cpp
@@ -204,7 +204,7 @@ OCL_PERF_TEST_P(RemapFixture, Remap,
const RemapParams params = GetParam();
const Size srcSize = get<0>(params);
const int type = get<1>(params), interpolation = get<2>(params), borderMode = BORDER_CONSTANT;
- const double eps = CV_MAT_DEPTH(type) <= CV_32S ? 1 : 1e-4;
+ //const double eps = CV_MAT_DEPTH(type) <= CV_32S ? 1 : 1e-4;
checkDeviceMaxMemoryAllocSize(srcSize, type);
diff --git a/modules/imgproc/src/imgwarp.cpp b/modules/imgproc/src/imgwarp.cpp
index 58ae385585..adc201acbe 100644
--- a/modules/imgproc/src/imgwarp.cpp
+++ b/modules/imgproc/src/imgwarp.cpp
@@ -1377,6 +1377,10 @@ static bool ocl_remap(InputArray _src, OutputArray _dst, InputArray _map1, Input
return k.run(2, globalThreads, NULL, false);
}
+#if 0
+/**
+@deprecated with old version of cv::linearPolar
+*/
static bool ocl_linearPolar(InputArray _src, OutputArray _dst,
Point2f center, double maxRadius, int flags)
{
@@ -1517,6 +1521,8 @@ static bool ocl_logPolar(InputArray _src, OutputArray _dst,
}
#endif
+#endif
+
#ifdef HAVE_OPENVX
static bool openvx_remap(Mat src, Mat dst, Mat map1, Mat map2, int interpolation, const Scalar& borderValue)
{
@@ -3252,397 +3258,86 @@ cvConvertMaps( const CvArr* arr1, const CvArr* arr2, CvArr* dstarr1, CvArr* dsta
cv::convertMaps( map1, map2, dstmap1, dstmap2, dstmap1.type(), false );
}
-/****************************************************************************************\
-* Log-Polar Transform *
-\****************************************************************************************/
-
-/* now it is done via Remap; more correct implementation should use
- some super-sampling technique outside of the "fovea" circle */
-CV_IMPL void
-cvLogPolar( const CvArr* srcarr, CvArr* dstarr,
- CvPoint2D32f center, double M, int flags )
-{
- Mat src_with_border; // don't scope this variable (it holds image data)
-
- cv::Ptr mapx, mapy;
-
- CvMat srcstub, *src = cvGetMat(srcarr, &srcstub);
- CvMat dststub, *dst = cvGetMat(dstarr, &dststub);
- CvSize dsize;
-
- if( !CV_ARE_TYPES_EQ( src, dst ))
- CV_Error( CV_StsUnmatchedFormats, "" );
-
- if( M <= 0 )
- CV_Error( CV_StsOutOfRange, "M should be >0" );
-
- dsize = cvGetMatSize(dst);
-
- mapx.reset(cvCreateMat( dsize.height, dsize.width, CV_32F ));
- mapy.reset(cvCreateMat( dsize.height, dsize.width, CV_32F ));
-
- if( !(flags & CV_WARP_INVERSE_MAP) )
- {
- int phi, rho;
- cv::AutoBuffer _exp_tab(dsize.width);
- double* exp_tab = _exp_tab;
-
- for( rho = 0; rho < dst->width; rho++ )
- exp_tab[rho] = std::exp(rho/M) - 1.0;
-
- for( phi = 0; phi < dsize.height; phi++ )
- {
- double cp = cos(phi*2*CV_PI/dsize.height);
- double sp = sin(phi*2*CV_PI/dsize.height);
- float* mx = (float*)(mapx->data.ptr + phi*mapx->step);
- float* my = (float*)(mapy->data.ptr + phi*mapy->step);
-
- for( rho = 0; rho < dsize.width; rho++ )
- {
- double r = exp_tab[rho];
- double x = r*cp + center.x;
- double y = r*sp + center.y;
-
- mx[rho] = (float)x;
- my[rho] = (float)y;
- }
- }
- }
- else
- {
- const int ANGLE_BORDER = 1;
- Mat src_ = cv::cvarrToMat(src);
- cv::copyMakeBorder(src_, src_with_border, ANGLE_BORDER, ANGLE_BORDER, 0, 0, BORDER_WRAP);
- srcstub = src_with_border; src = &srcstub;
- CvSize ssize = cvGetMatSize(src);
- ssize.height -= 2*ANGLE_BORDER;
-
- int x, y;
- CvMat bufx, bufy, bufp, bufa;
- double ascale = ssize.height/(2*CV_PI);
- cv::AutoBuffer _buf(4*dsize.width);
- float* buf = _buf;
-
- bufx = cvMat( 1, dsize.width, CV_32F, buf );
- bufy = cvMat( 1, dsize.width, CV_32F, buf + dsize.width );
- bufp = cvMat( 1, dsize.width, CV_32F, buf + dsize.width*2 );
- bufa = cvMat( 1, dsize.width, CV_32F, buf + dsize.width*3 );
-
- for( x = 0; x < dsize.width; x++ )
- bufx.data.fl[x] = (float)x - center.x;
-
- for( y = 0; y < dsize.height; y++ )
- {
- float* mx = (float*)(mapx->data.ptr + y*mapx->step);
- float* my = (float*)(mapy->data.ptr + y*mapy->step);
-
- for( x = 0; x < dsize.width; x++ )
- bufy.data.fl[x] = (float)y - center.y;
-
-#if 1
- cvCartToPolar( &bufx, &bufy, &bufp, &bufa );
-
- for( x = 0; x < dsize.width; x++ )
- bufp.data.fl[x] += 1.f;
-
- cvLog( &bufp, &bufp );
-
- for( x = 0; x < dsize.width; x++ )
- {
- double rho = bufp.data.fl[x]*M;
- double phi = bufa.data.fl[x]*ascale;
-
- mx[x] = (float)rho;
- my[x] = (float)phi + ANGLE_BORDER;
- }
-#else
- for( x = 0; x < dsize.width; x++ )
- {
- double xx = bufx.data.fl[x];
- double yy = bufy.data.fl[x];
-
- double p = log(std::sqrt(xx*xx + yy*yy) + 1.)*M;
- double a = atan2(yy,xx);
- if( a < 0 )
- a = 2*CV_PI + a;
- a *= ascale;
-
- mx[x] = (float)p;
- my[x] = (float)a;
- }
-#endif
- }
- }
-
- cvRemap( src, dst, mapx, mapy, flags, cvScalarAll(0) );
-}
-
-void cv::logPolar( InputArray _src, OutputArray _dst,
- Point2f center, double M, int flags )
-{
- CV_INSTRUMENT_REGION()
-
- CV_OCL_RUN(_src.isUMat() && _dst.isUMat(),
- ocl_logPolar(_src, _dst, center, M, flags));
- Mat src_with_border; // don't scope this variable (it holds image data)
-
- Mat mapx, mapy;
-
- Mat srcstub, src = _src.getMat();
- _dst.create(src.size(), src.type());
- Size dsize = src.size();
-
- if (M <= 0)
- CV_Error(CV_StsOutOfRange, "M should be >0");
-
-
- mapx.create(dsize, CV_32F);
- mapy.create(dsize, CV_32F);
-
- if (!(flags & CV_WARP_INVERSE_MAP))
- {
- int phi, rho;
- cv::AutoBuffer _exp_tab(dsize.width);
- double* exp_tab = _exp_tab;
-
- for (rho = 0; rho < dsize.width; rho++)
- exp_tab[rho] = std::exp(rho / M) - 1.0;
-
- for (phi = 0; phi < dsize.height; phi++)
- {
- double cp = std::cos(phi * 2 * CV_PI / dsize.height);
- double sp = std::sin(phi * 2 * CV_PI / dsize.height);
- float* mx = (float*)(mapx.data + phi*mapx.step);
- float* my = (float*)(mapy.data + phi*mapy.step);
-
- for (rho = 0; rho < dsize.width; rho++)
- {
- double r = exp_tab[rho];
- double x = r*cp + center.x;
- double y = r*sp + center.y;
-
- mx[rho] = (float)x;
- my[rho] = (float)y;
- }
- }
- }
- else
- {
- const int ANGLE_BORDER = 1;
- cv::copyMakeBorder(src, src_with_border, ANGLE_BORDER, ANGLE_BORDER, 0, 0, BORDER_WRAP);
- srcstub = src_with_border; src = srcstub;
- Size ssize = src.size();
- ssize.height -= 2 * ANGLE_BORDER;
-
- int x, y;
- Mat bufx, bufy, bufp, bufa;
- double ascale = ssize.height / (2 * CV_PI);
-
- bufx = Mat(1, dsize.width, CV_32F);
- bufy = Mat(1, dsize.width, CV_32F);
- bufp = Mat(1, dsize.width, CV_32F);
- bufa = Mat(1, dsize.width, CV_32F);
-
- for (x = 0; x < dsize.width; x++)
- bufx.at(0, x) = (float)x - center.x;
-
- for (y = 0; y < dsize.height; y++)
- {
- float* mx = (float*)(mapx.data + y*mapx.step);
- float* my = (float*)(mapy.data + y*mapy.step);
-
- for (x = 0; x < dsize.width; x++)
- bufy.at(0, x) = (float)y - center.y;
-
-#if 1
- cartToPolar(bufx, bufy, bufp, bufa);
-
- for (x = 0; x < dsize.width; x++)
- bufp.at(0, x) += 1.f;
-
- log(bufp, bufp);
-
- for (x = 0; x < dsize.width; x++)
- {
- double rho = bufp.at(0, x) * M;
- double phi = bufa.at(0, x) * ascale;
-
- mx[x] = (float)rho;
- my[x] = (float)phi + ANGLE_BORDER;
- }
-#else
- for (x = 0; x < dsize.width; x++)
- {
- double xx = bufx.at(0, x);
- double yy = bufy.at(0, x);
- double p = log(std::sqrt(xx*xx + yy*yy) + 1.)*M;
- double a = atan2(yy, xx);
- if (a < 0)
- a = 2 * CV_PI + a;
- a *= ascale;
- mx[x] = (float)p;
- my[x] = (float)a;
- }
-#endif
- }
- }
-
- remap(src, _dst, mapx, mapy, flags & cv::INTER_MAX,
- (flags & CV_WARP_FILL_OUTLIERS) ? cv::BORDER_CONSTANT : cv::BORDER_TRANSPARENT);
-}
-
/****************************************************************************************
- Linear-Polar Transform
- J.L. Blanco, Apr 2009
- ****************************************************************************************/
-CV_IMPL
-void cvLinearPolar( const CvArr* srcarr, CvArr* dstarr,
- CvPoint2D32f center, double maxRadius, int flags )
+PkLab.net 2018 based on cv::linearPolar from OpenCV by J.L. Blanco, Apr 2009
+****************************************************************************************/
+void cv::warpPolar(InputArray _src, OutputArray _dst, Size dsize,
+ Point2f center, double maxRadius, int flags)
{
- Mat src_with_border; // don't scope this variable (it holds image data)
-
- cv::Ptr mapx, mapy;
-
- CvMat srcstub, *src = (CvMat*)srcarr;
- CvMat dststub, *dst = (CvMat*)dstarr;
- CvSize dsize;
-
- src = cvGetMat( srcarr, &srcstub,0,0 );
- dst = cvGetMat( dstarr, &dststub,0,0 );
-
- if( !CV_ARE_TYPES_EQ( src, dst ))
- CV_Error( CV_StsUnmatchedFormats, "" );
-
- dsize = cvGetMatSize(dst);
-
- mapx.reset(cvCreateMat( dsize.height, dsize.width, CV_32F ));
- mapy.reset(cvCreateMat( dsize.height, dsize.width, CV_32F ));
-
- if( !(flags & CV_WARP_INVERSE_MAP) )
+ // if dest size is empty given than calculate using proportional setting
+ // thus we calculate needed angles to keep same area as bounding circle
+ if ((dsize.width <= 0) && (dsize.height <= 0))
{
- int phi, rho;
-
- for( phi = 0; phi < dsize.height; phi++ )
- {
- double cp = cos(phi*2*CV_PI/dsize.height);
- double sp = sin(phi*2*CV_PI/dsize.height);
- float* mx = (float*)(mapx->data.ptr + phi*mapx->step);
- float* my = (float*)(mapy->data.ptr + phi*mapy->step);
-
- for( rho = 0; rho < dsize.width; rho++ )
- {
- double r = maxRadius*rho/dsize.width;
- double x = r*cp + center.x;
- double y = r*sp + center.y;
-
- mx[rho] = (float)x;
- my[rho] = (float)y;
- }
- }
+ dsize.width = cvRound(maxRadius);
+ dsize.height = cvRound(maxRadius * CV_PI);
}
- else
+ else if (dsize.height <= 0)
{
- const int ANGLE_BORDER = 1;
- Mat src_ = cv::cvarrToMat(src);
- cv::copyMakeBorder(src_, src_with_border, ANGLE_BORDER, ANGLE_BORDER, 0, 0, BORDER_WRAP);
- srcstub = src_with_border; src = &srcstub;
- CvSize ssize = cvGetMatSize(src);
- ssize.height -= 2*ANGLE_BORDER;
-
- int x, y;
- CvMat bufx, bufy, bufp, bufa;
- const double ascale = ssize.height/(2*CV_PI);
- const double pscale = ssize.width/maxRadius;
-
- cv::AutoBuffer _buf(4*dsize.width);
- float* buf = _buf;
-
- bufx = cvMat( 1, dsize.width, CV_32F, buf );
- bufy = cvMat( 1, dsize.width, CV_32F, buf + dsize.width );
- bufp = cvMat( 1, dsize.width, CV_32F, buf + dsize.width*2 );
- bufa = cvMat( 1, dsize.width, CV_32F, buf + dsize.width*3 );
-
- for( x = 0; x < dsize.width; x++ )
- bufx.data.fl[x] = (float)x - center.x;
-
- for( y = 0; y < dsize.height; y++ )
- {
- float* mx = (float*)(mapx->data.ptr + y*mapx->step);
- float* my = (float*)(mapy->data.ptr + y*mapy->step);
-
- for( x = 0; x < dsize.width; x++ )
- bufy.data.fl[x] = (float)y - center.y;
-
- cvCartToPolar( &bufx, &bufy, &bufp, &bufa, 0 );
-
- for( x = 0; x < dsize.width; x++ )
- {
- double rho = bufp.data.fl[x]*pscale;
- double phi = bufa.data.fl[x]*ascale;
- mx[x] = (float)rho;
- my[x] = (float)phi + ANGLE_BORDER;
- }
- }
+ dsize.height = cvRound(dsize.width * CV_PI);
}
- cvRemap( src, dst, mapx, mapy, flags, cvScalarAll(0) );
-}
-
-void cv::linearPolar( InputArray _src, OutputArray _dst,
- Point2f center, double maxRadius, int flags )
-{
- CV_INSTRUMENT_REGION()
-
- CV_OCL_RUN(_src.isUMat() && _dst.isUMat(),
- ocl_linearPolar(_src, _dst, center, maxRadius, flags));
- Mat src_with_border; // don't scope this variable (it holds image data)
-
Mat mapx, mapy;
- Mat srcstub, src = _src.getMat();
- _dst.create(src.size(), src.type());
- Size dsize = src.size();
-
-
mapx.create(dsize, CV_32F);
mapy.create(dsize, CV_32F);
+ bool semiLog = (flags & WARP_POLAR_LOG) != 0;
if (!(flags & CV_WARP_INVERSE_MAP))
{
+ double Kangle = CV_2PI / dsize.height;
int phi, rho;
+ // precalculate scaled rho
+ Mat rhos = Mat(1, dsize.width, CV_32F);
+ float* bufRhos = (float*)(rhos.data);
+ if (semiLog)
+ {
+ double Kmag = std::log(maxRadius) / dsize.width;
+ for (rho = 0; rho < dsize.width; rho++)
+ bufRhos[rho] = (float)(std::exp(rho * Kmag) - 1.0);
+
+ }
+ else
+ {
+ double Kmag = maxRadius / dsize.width;
+ for (rho = 0; rho < dsize.width; rho++)
+ bufRhos[rho] = (float)(rho * Kmag);
+ }
+
for (phi = 0; phi < dsize.height; phi++)
{
- double cp = std::cos(phi * 2 * CV_PI / dsize.height);
- double sp = std::sin(phi * 2 * CV_PI / dsize.height);
+ double KKy = Kangle * phi;
+ double cp = std::cos(KKy);
+ double sp = std::sin(KKy);
float* mx = (float*)(mapx.data + phi*mapx.step);
float* my = (float*)(mapy.data + phi*mapy.step);
for (rho = 0; rho < dsize.width; rho++)
{
- double r = maxRadius*rho / dsize.width;
- double x = r*cp + center.x;
- double y = r*sp + center.y;
+ double x = bufRhos[rho] * cp + center.x;
+ double y = bufRhos[rho] * sp + center.y;
mx[rho] = (float)x;
my[rho] = (float)y;
}
}
+ remap(_src, _dst, mapx, mapy, flags & cv::INTER_MAX, (flags & CV_WARP_FILL_OUTLIERS) ? cv::BORDER_CONSTANT : cv::BORDER_TRANSPARENT);
}
else
{
const int ANGLE_BORDER = 1;
-
- cv::copyMakeBorder(src, src_with_border, ANGLE_BORDER, ANGLE_BORDER, 0, 0, BORDER_WRAP);
- src = src_with_border;
- Size ssize = src_with_border.size();
+ cv::copyMakeBorder(_src, _dst, ANGLE_BORDER, ANGLE_BORDER, 0, 0, BORDER_WRAP);
+ Mat src = _dst.getMat();
+ Size ssize = _dst.size();
ssize.height -= 2 * ANGLE_BORDER;
+ const double Kangle = CV_2PI / ssize.height;
+ double Kmag;
+ if (semiLog)
+ Kmag = std::log(maxRadius) / ssize.width;
+ else
+ Kmag = maxRadius / ssize.width;
int x, y;
Mat bufx, bufy, bufp, bufa;
- const double ascale = ssize.height / (2 * CV_PI);
- const double pscale = ssize.width / maxRadius;
-
-
bufx = Mat(1, dsize.width, CV_32F);
bufy = Mat(1, dsize.width, CV_32F);
@@ -3662,17 +3357,63 @@ void cv::linearPolar( InputArray _src, OutputArray _dst,
cartToPolar(bufx, bufy, bufp, bufa, 0);
+ if (semiLog)
+ {
+ bufp += 1.f;
+ log(bufp, bufp);
+ }
+
for (x = 0; x < dsize.width; x++)
{
- double rho = bufp.at(0, x) * pscale;
- double phi = bufa.at(0, x) * ascale;
+ double rho = bufp.at(0, x) / Kmag;
+ double phi = bufa.at(0, x) / Kangle;
mx[x] = (float)rho;
my[x] = (float)phi + ANGLE_BORDER;
}
}
+ remap(src, _dst, mapx, mapy, flags & cv::INTER_MAX,
+ (flags & CV_WARP_FILL_OUTLIERS) ? cv::BORDER_CONSTANT : cv::BORDER_TRANSPARENT);
}
+}
- remap(src, _dst, mapx, mapy, flags & cv::INTER_MAX, (flags & CV_WARP_FILL_OUTLIERS) ? cv::BORDER_CONSTANT : cv::BORDER_TRANSPARENT);
+void cv::linearPolar( InputArray _src, OutputArray _dst,
+ Point2f center, double maxRadius, int flags )
+{
+ warpPolar(_src, _dst, _src.size(), center, maxRadius, flags & ~WARP_POLAR_LOG);
+}
+
+void cv::logPolar( InputArray _src, OutputArray _dst,
+ Point2f center, double maxRadius, int flags )
+{
+ Size ssize = _src.size();
+ double M = maxRadius > 0 ? std::exp(ssize.width / maxRadius) : 1;
+ warpPolar(_src, _dst, ssize, center, M, flags | WARP_POLAR_LOG);
+}
+
+CV_IMPL
+void cvLinearPolar( const CvArr* srcarr, CvArr* dstarr,
+ CvPoint2D32f center, double maxRadius, int flags )
+{
+ Mat src = cvarrToMat(srcarr);
+ Mat dst = cvarrToMat(dstarr);
+
+ CV_Assert(src.size == dst.size);
+ CV_Assert(src.type() == dst.type());
+
+ cv::linearPolar(src, dst, center, maxRadius, flags);
+}
+
+CV_IMPL
+void cvLogPolar( const CvArr* srcarr, CvArr* dstarr,
+ CvPoint2D32f center, double M, int flags )
+{
+ Mat src = cvarrToMat(srcarr);
+ Mat dst = cvarrToMat(dstarr);
+
+ CV_Assert(src.size == dst.size);
+ CV_Assert(src.type() == dst.type());
+
+ cv::logPolar(src, dst, center, M, flags);
}
/* End of file. */
diff --git a/modules/imgproc/test/test_imgwarp.cpp b/modules/imgproc/test/test_imgwarp.cpp
index 62907c4d17..741ec7736e 100644
--- a/modules/imgproc/test/test_imgwarp.cpp
+++ b/modules/imgproc/test/test_imgwarp.cpp
@@ -1781,7 +1781,7 @@ TEST(Imgproc_Remap, DISABLED_memleak)
}
}
-
+//** @deprecated */
TEST(Imgproc_linearPolar, identity)
{
const int N = 33;
@@ -1821,7 +1821,7 @@ TEST(Imgproc_linearPolar, identity)
#endif
}
-
+//** @deprecated */
TEST(Imgproc_logPolar, identity)
{
const int N = 33;
@@ -1862,6 +1862,52 @@ TEST(Imgproc_logPolar, identity)
#endif
}
+TEST(Imgproc_warpPolar, identity)
+{
+ const int N = 33;
+ Mat in(N, N, CV_8UC3, Scalar(255, 0, 0));
+ in(cv::Rect(N / 3, N / 3, N / 3, N / 3)).setTo(Scalar::all(255));
+ cv::blur(in, in, Size(5, 5));
+ cv::blur(in, in, Size(5, 5));
+
+ Mat src = in.clone();
+ Mat dst;
+
+ Rect roi = Rect(0, 0, in.cols - ((N + 19) / 20), in.rows);
+ Point2f center = Point2f((N - 1) * 0.5f, (N - 1) * 0.5f);
+ double radius = N * 0.5;
+ int flags = CV_WARP_FILL_OUTLIERS | CV_INTER_LINEAR;
+ // test linearPolar
+ for (int ki = 1; ki <= 5; ki++)
+ {
+ warpPolar(src, dst, src.size(), center, radius, flags + WARP_POLAR_LINEAR + CV_WARP_INVERSE_MAP);
+ warpPolar(dst, src, src.size(), center, radius, flags + WARP_POLAR_LINEAR);
+
+ double psnr = cv::PSNR(in(roi), src(roi));
+ EXPECT_LE(25, psnr) << "iteration=" << ki;
+ }
+ // test logPolar
+ src = in.clone();
+ for (int ki = 1; ki <= 5; ki++)
+ {
+ warpPolar(src, dst, src.size(),center, radius, flags + WARP_POLAR_LOG + CV_WARP_INVERSE_MAP );
+ warpPolar(dst, src, src.size(),center, radius, flags + WARP_POLAR_LOG);
+
+ double psnr = cv::PSNR(in(roi), src(roi));
+ EXPECT_LE(25, psnr) << "iteration=" << ki;
+ }
+
+#if 0
+ Mat all(N*2+2,N*2+2, src.type(), Scalar(0,0,255));
+ in.copyTo(all(Rect(0,0,N,N)));
+ src.copyTo(all(Rect(0,N+1,N,N)));
+ src.copyTo(all(Rect(N+1,0,N,N)));
+ dst.copyTo(all(Rect(N+1,N+1,N,N)));
+ imwrite("linearPolar.png", all);
+ imshow("input", in); imshow("result", dst); imshow("restore", src); imshow("all", all);
+ cv::waitKey();
+#endif
+}
}} // namespace
/* End of file. */
diff --git a/samples/cpp/polar_transforms.cpp b/samples/cpp/polar_transforms.cpp
index d860e27981..4a6014f433 100644
--- a/samples/cpp/polar_transforms.cpp
+++ b/samples/cpp/polar_transforms.cpp
@@ -43,33 +43,82 @@ int main( int argc, char** argv )
moveWindow( "Log-Polar", 700,20 );
moveWindow( "Recovered Linear-Polar", 20, 350 );
moveWindow( "Recovered Log-Polar", 700, 350 );
-
+ int flags = INTER_LINEAR + WARP_FILL_OUTLIERS;
+ Mat src;
for(;;)
{
- Mat frame;
- capture >> frame;
+ capture >> src;
- if( frame.empty() )
+ if(src.empty() )
break;
- Point2f center( (float)frame.cols / 2, (float)frame.rows / 2 );
- double M = 70;
+ Point2f center( (float)src.cols / 2, (float)src.rows / 2 );
+ double maxRadius = 0.7*min(center.y, center.x);
- logPolar(frame,log_polar_img, center, M, INTER_LINEAR + WARP_FILL_OUTLIERS);
- linearPolar(frame,lin_polar_img, center, M, INTER_LINEAR + WARP_FILL_OUTLIERS);
+#if 0 //deprecated
+ double M = frame.cols / log(maxRadius);
+ logPolar(frame, log_polar_img, center, M, flags);
+ linearPolar(frame, lin_polar_img, center, maxRadius, flags);
- logPolar(log_polar_img, recovered_log_polar, center, M, WARP_INVERSE_MAP + INTER_LINEAR);
- linearPolar(lin_polar_img, recovered_lin_polar_img, center, M, WARP_INVERSE_MAP + INTER_LINEAR + WARP_FILL_OUTLIERS);
+ logPolar(log_polar_img, recovered_log_polar, center, M, flags + WARP_INVERSE_MAP);
+ linearPolar(lin_polar_img, recovered_lin_polar_img, center, maxRadius, flags + WARP_INVERSE_MAP);
+#endif
+ //! [InverseMap]
+ // direct transform
+ warpPolar(src, lin_polar_img, Size(),center, maxRadius, flags); // linear Polar
+ warpPolar(src, log_polar_img, Size(),center, maxRadius, flags + WARP_POLAR_LOG); // semilog Polar
+ // inverse transform
+ warpPolar(lin_polar_img, recovered_lin_polar_img, src.size(), center, maxRadius, flags + WARP_INVERSE_MAP);
+ warpPolar(log_polar_img, recovered_log_polar, src.size(), center, maxRadius, flags + WARP_POLAR_LOG + WARP_INVERSE_MAP);
+ //! [InverseMap]
- imshow("Log-Polar", log_polar_img );
- imshow("Linear-Polar", lin_polar_img );
+ // Below is the reverse transformation for (rho, phi)->(x, y) :
+ Mat dst;
+ if (flags & WARP_POLAR_LOG)
+ dst = log_polar_img;
+ else
+ dst = lin_polar_img;
+ //get a point from the polar image
+ int rho = cvRound(dst.cols * 0.75);
+ int phi = cvRound(dst.rows / 2.0);
+
+ //! [InverseCoordinate]
+ double angleRad, magnitude;
+ double Kangle = dst.rows / CV_2PI;
+ angleRad = phi / Kangle;
+ if (flags & WARP_POLAR_LOG)
+ {
+ double Klog = dst.cols / std::log(maxRadius);
+ magnitude = std::exp(rho / Klog);
+ }
+ else
+ {
+ double Klin = dst.cols / maxRadius;
+ magnitude = rho / Klin;
+ }
+ int x = cvRound(center.x + magnitude * cos(angleRad));
+ int y = cvRound(center.y + magnitude * sin(angleRad));
+ //! [InverseCoordinate]
+ drawMarker(src, Point(x, y), Scalar(0, 255, 0));
+ drawMarker(dst, Point(rho, phi), Scalar(0, 255, 0));
+
+
+#if 0 //C version
+ CvMat src = frame;
+ CvMat dst = lin_polar_img;
+ CvMat inverse = recovered_lin_polar_img;
+ cvLinearPolar(&src, &dst, center, maxRadius, flags);
+ cvLinearPolar(&dst, &inverse, center, maxRadius,flags + WARP_INVERSE_MAP);
+#endif
+
+ imshow("Src frame", src);
+ imshow("Log-Polar", log_polar_img);
+ imshow("Linear-Polar", lin_polar_img);
imshow("Recovered Linear-Polar", recovered_lin_polar_img );
imshow("Recovered Log-Polar", recovered_log_polar );
if( waitKey(10) >= 0 )
break;
}
-
- waitKey(0);
return 0;
}