OPenCV版本:4.4
IDE:VS2019
功能描述
将图像重新映射到极坐标或半对数极坐标空间,这个函数用于实现图像的极坐标变换。
使用以下变换来转换图像:
d
s
t
(
ρ
,
ϕ
)
=
s
r
c
(
x
,
y
)
dst(\rho , \phi ) = src(x,y)
dst(ρ,ϕ)=src(x,y)
此处:
I
⃗
=
(
x
−
c
e
n
t
e
r
.
x
,
y
−
c
e
n
t
e
r
.
y
)
ϕ
=
K
a
n
g
l
e
⋅
angle
(
I
⃗
)
ρ
=
{
K
l
i
n
⋅
magnitude
(
I
⃗
)
d
e
f
a
u
l
t
K
l
o
g
⋅
l
o
g
e
(
magnitude
(
I
⃗
)
)
i
f
s
e
m
i
l
o
g
\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}
I=(x−center.x,y−center.y)ϕ=Kangle⋅angle(I)ρ={Klin⋅magnitude(I)Klog⋅loge(magnitude(I))defaultifsemilog
并且:
K
a
n
g
l
e
=
d
s
i
z
e
.
h
e
i
g
h
t
/
2
Π
K
l
i
n
=
d
s
i
z
e
.
w
i
d
t
h
/
m
a
x
R
a
d
i
u
s
K
l
o
g
=
d
s
i
z
e
.
w
i
d
t
h
/
l
o
g
e
(
m
a
x
R
a
d
i
u
s
)
\begin{array}{l} Kangle = dsize.height / 2\Pi \\ Klin = dsize.width / maxRadius \\ Klog = dsize.width / log_e(maxRadius) \\ \end{array}
Kangle=dsize.height/2ΠKlin=dsize.width/maxRadiusKlog=dsize.width/loge(maxRadius)
线性与半对数映射
极坐标映射可以是线性或半对数,添加WarpPolarMode中的一个到flags来确定极坐标映射模式,。
线性是缺省模式。
半对数映射模拟人类的“中心凹”视觉,允许在视线(中心视觉)上具有非常高的锐度,而周围视觉的锐度较小。
dsize的选项:
- 如果dsize中的两个值均<=0(默认),则目标图像将具有(几乎)相同的源边界圆面积
d s i z e . a r e a ← ( m a x R a d i u s 2 ⋅ Π ) d s i z e . w i d t h = cvRound ( m a x R a d i u s ) d s i z e . h e i g h t = cvRound ( m a x R a d i u s ⋅ Π ) \begin{array}{l} dsize.area \leftarrow (maxRadius^2 \cdot \Pi) \\ dsize.width = \texttt{cvRound}(maxRadius) \\ dsize.height = \texttt{cvRound}(maxRadius \cdot \Pi) \\ \end{array} dsize.area←(maxRadius2⋅Π)dsize.width=cvRound(maxRadius)dsize.height=cvRound(maxRadius⋅Π) - 如果只是 dsize.height <= 0,目标图像区域将与边界圆区域按比例Kx * Kx:缩放。
d s i z e . h e i g h t = cvRound ( d s i z e . w i d t h ⋅ Π ) \begin{array}{l} dsize.height = \texttt{cvRound}(dsize.width \cdot \Pi) \\ \end{array} dsize.height=cvRound(dsize.width⋅Π) - 如果dsize所有的成员的值都 > 0, 目标图像将具有给定的大小,因此边界圆的面积将缩放为dsize.
反向映射
你可以通过添加WARP_INVERSE_MAP到flags获取反向映射。
// 直接变换
warpPolar(src, lin_polar_img, Size(),center, maxRadius, flags);
// 线性极坐标
warpPolar(src, log_polar_img, Size(),center, maxRadius, flags + WARP_POLAR_LOG);
// 半对数极坐标
// 反变换
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);
在编程中,通过(ρ,φ)−>(x,y)从极坐标计算原始坐标:
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));
函数原型
void cv::warpPolar ( InputArray src,
OutputArray dst,
Size dsize,
Point2f center,
double maxRadius,
int flags
)
参数
- src 源图像.
- dst 目标图像,类型和src相同.
- dsize 目标图像大小 (see description for valid options).
- center 转换中心 The transformation center.
- maxRadius 要变换的边界圆的半径,它还确定了逆震级比例参数。
flags 插值方法的组合, InterpolationFlags + WarpPolarMode. - 添加 WARP_POLAR_LINEAR 选择线性极坐标映射 (默认)
- 添加 WARP_POLAR_LOG 选择半对数极映射。
- 添加 WARP_INVERSE_MAP 选择反向映射
Note
- 本函数不支持就地转换。
- 为了计算幅值和角度,内部使用cartToPolar,因此角度的测量范围为0到360度,精度约为0.3度。
- 此函数使用remap。由于当前实现的限制,输入和输出图像的大小应小于32767x32767.
另请参见
cv::remap
示例代码
#include <iostream>
#include <opencv2/opencv.hpp>
#include <vector>
using namespace cv;
int main(int argc, char** argv)
{
VideoCapture capture;
Mat log_polar_img, lin_polar_img, recovered_log_polar, recovered_lin_polar_img;
CommandLineParser parser(argc, argv, "{@input|0| camera device number or video file path}");
parser.about("\nThis program illustrates usage of Linear-Polar and Log-Polar image transforms\n");
parser.printMessage();
std::string arg = parser.get<std::string>("@input");
//if (arg.size() == 1 && isdigit(arg[0]))
// capture.open(arg[0] - '0');
//else
// capture.open(samples::findFileOrKeep(arg));
capture.open("D:\\OpenCVtest\\video1.mp4");
if (!capture.isOpened())
{
fprintf(stderr, "Could not initialize capturing...\n");
return -1;
}
namedWindow("Linear-Polar", WINDOW_AUTOSIZE);
namedWindow("Log-Polar", WINDOW_AUTOSIZE);
namedWindow("Recovered Linear-Polar", WINDOW_AUTOSIZE);
namedWindow("Recovered Log-Polar", WINDOW_AUTOSIZE);
moveWindow("Linear-Polar", 20, 20);
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 (;;)
{
capture >> src;
if (src.empty())
break;
Point2f center((float)src.cols / 2, (float)src.rows / 2);
double maxRadius = 0.7 * min(center.y, center.x);
#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, flags + WARP_INVERSE_MAP);
linearPolar(lin_polar_img, recovered_lin_polar_img, center, maxRadius, flags + WARP_INVERSE_MAP);
#endif
// 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);
// 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);
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));
drawMarker(src, Point(x, y), Scalar(0, 255, 0));
drawMarker(dst, Point(rho, phi), Scalar(0, 255, 0));
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;
}
return 0;
}
运行结果
原图:
线性极坐标映射:
半对数极映射
恢复的线性极坐标映射:
恢复的半对数极映射