OpenCV几何图像变换(11)极坐标转换函数warpPolar()的使用
- 操作系统:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 编程语言:C++11
算法描述
函数将图像重映射到极坐标或半对数极坐标空间。



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
⃗
)
默认
K
l
o
g
⋅
l
o
g
e
(
magnitude
(
I
⃗
)
)
i
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}) & 默认 \\ Klog \cdot log_e(\texttt{magnitude} (\vec{I})) & if \; 半对数 \\ \end{matrix}\right. \end{array}
I=(x−center.x,y−center.y)ϕ=Kangle⋅angle(I)ρ={Klin⋅magnitude(I)Klog⋅loge(magnitude(I))默认if半对数
并且
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 来指定极坐标映射模式。
线性是默认模式。
半对数映射模拟人类“中央视觉”的特性,即视线中心的视觉敏锐度非常高,而周边视觉的敏锐度较低。
关于 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 来获得反向映射。
// 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);
另外,要从极坐标映射坐标 (rho, phi) 计算原始坐标 (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));
在OpenCV中,warpPolar函数用于将图像从笛卡尔坐标系转换到极坐标系或从极坐标系转换回笛卡尔坐标系。这种变换对于进行圆形图像处理非常有用,例如检测圆环状特征或进行图像的径向滤波。
函数原型
void cv::warpPolar
(
InputArray src,
OutputArray dst,
Size dsize,
Point2f center,
double maxRadius,
int flags
)
参数
- 参数src 源图像。
- 参数dst 目标图像。它将具有与 src 相同的类型。
- 参数 dsize 目标图像的大小(参见描述中的有效选项)。
- 参数center 转换的中心点。
- 参数maxRadius 包围圆的半径来进行转换。它还确定了逆向的幅度比例参数。
- flags: 插值方法的组合,InterpolationFlags + WarpPolarMode。
- 添加 WARP_POLAR_LINEAR 来选择线性极坐标映射(默认)
- 添加 WARP_POLAR_LOG 来选择半对数极坐标映射
- 添加 WARP_INVERSE_MAP 来进行反向映射
注意事项
该函数不能原地操作。
为了计算幅度和角度(以度为单位),内部使用 cartToPolar 函数,因此角度范围是从 0 到 360 度,精度约为 0.3 度。
此函数使用 remap。由于当前实现的限制,输入和输出图像的大小应该小于 32767x32767。
代码示例
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/opencv.hpp>
using namespace cv;
int main( int argc, char** argv )
{
// 读取图像
Mat image = imread( "/media/dingxin/data/study/OpenCV/sources/images/circle2.jpg", IMREAD_GRAYSCALE );
if ( image.empty() )
{
std::cerr << "Error: Could not open or find the image." << std::endl;
return -1;
}
// 设置极坐标变换的中心点
Point2f center( image.cols / 2.0, image.rows / 2.0 );
// 设置最大半径
double maxRadius = std::min( image.cols, image.rows ) / 2.0;
// 设置输出图像的大小
Size dsize( 360, maxRadius ); // 360度,半径为最大半径
// 创建输出图像
Mat polarImage;
// 应用极坐标变换
warpPolar( image, polarImage, dsize, center, maxRadius, WARP_POLAR_LINEAR + INTER_LINEAR);
// 显示结果
namedWindow( "Original Image", WINDOW_NORMAL );
imshow( "Original Image", image );
namedWindow( "Polar Image", WINDOW_NORMAL );
imshow( "Polar Image", polarImage );
waitKey( 0 );
return 0;
}