Rewite polar transforms (#11323)

* Rewrite polar transformations

- A new wrapPolar function encapsulate both linear and semi-log remap
- Destination size is a parameter or calculated automatically to keep objects size between remapping
- linearPolar and logPolar has been deprecated

* Fix build warning and error in accuracy test

* Fix function name to warpPolar

* Explicitly specify the mapping mode, so we retain all the parameters as non-optional.

Introduces WarpPolarMode enum to specify the mapping mode in flags

* resolves performance warning on windows build

* removed duplicated logPolar and linearPolar implementations
This commit is contained in:
Vadim Pisarevsky 2018-04-17 15:50:52 +03:00 committed by GitHub
parent e0fef2bca1
commit b8b7ca7302
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 2589 additions and 3123 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 KiB

After

Width:  |  Height:  |  Size: 285 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 242 KiB

After

Width:  |  Height:  |  Size: 325 KiB

View File

@ -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
![Polar remaps reference](pics/polar_remap_doc.png)
@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
![Polar remaps reference](pics/polar_remap_doc.png)
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

View File

@ -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,

View File

@ -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);

View File

@ -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<CvMat> 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<double> _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<float> _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<double> _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<float>(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<float>(0, x) = (float)y - center.y;
#if 1
cartToPolar(bufx, bufy, bufp, bufa);
for (x = 0; x < dsize.width; x++)
bufp.at<float>(0, x) += 1.f;
log(bufp, bufp);
for (x = 0; x < dsize.width; x++)
{
double rho = bufp.at<float>(0, x) * M;
double phi = bufa.at<float>(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<float>(0, x);
double yy = bufy.at<float>(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<CvMat> 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<float> _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<float>(0, x) * pscale;
double phi = bufa.at<float>(0, x) * ascale;
double rho = bufp.at<float>(0, x) / Kmag;
double phi = bufa.at<float>(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. */

View File

@ -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. */

View File

@ -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;
}