mirror of
https://github.com/opencv/opencv.git
synced 2025-01-18 14:13:15 +08:00
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:
parent
e0fef2bca1
commit
b8b7ca7302
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 |
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user