第二节 图像几何变换
本节中的功能执行2D图像的各种几何变换。 它们不更改图像内容,而是使像素网格变形并将该变形的网格映射到目标图像。实际上,避免采样伪像,以从目标到源的相反顺序进行映射。 也就是说,对于目标图像的每个像素 ( x , y ) (x,y) (x,y),函数计算源图像中相应原像素的坐标并复制像素值:
dst ( x , y ) = src ( f x ( x , y ) , f y ( x , y ) ) \texttt{dst} (x,y)= \texttt{src} (f_x(x,y), f_y(x,y)) dst(x,y)=src(fx(x,y),fy(x,y))
如果指定前向映射, < g x , g y > : src → dst \left<g_x, g_y\right>: \texttt{src} \rightarrow \texttt{dst} ⟨gx,gy⟩:src→dst,OpenCV函数首先计算对应的逆映射 < f x , f y > : dst → src \left<f_x, f_y\right>: \texttt{dst} \rightarrow \texttt{src} ⟨fx,fy⟩:dst→src,然后使用上面的公式。
从最通用的重新映射到最简单,最快的尺寸调整,几何转换的实际实现需要使用上述公式解决两个主要问题:
- 不存在像素的外推。 与上一部分中描述的过滤功能相似,对于某些 ( x , y ) (x,y) (x,y), f x ( x , y ) f_x(x,y) fx(x,y)或 f y ( x , y ) f_y(x,y) fy(x,y)中的一个可能会落在图像之外。 在这种情况下,需要使用外推方法。 OpenCV提供与过滤功能相同的外推方法选择。 此外,它提供了BORDER_TRANSPARENT方法。 这意味着目标图像中的相应像素将完全不会被修改。
- 像素值的插值。 通常 f x ( x , y ) f_x(x,y) fx(x,y)和 f y ( x , y ) f_y(x,y) fy(x,y)是浮点数。 这意味着 ⟨ f x , f y ⟩ ⟨fx,fy⟩ ⟨fx,fy⟩可以是仿射或透视变换,也可以是径向镜头畸变校正,依此类推。 因此,需要检索小数坐标处的像素值。 在最简单的情况下,可以将坐标仅舍入为最接近的整数坐标,并可以使用相应的像素。 这称为最近邻插值。 但是,通过使用更复杂的插值方法可以获得更好的结果,其中将多项式函数拟合到计算像素的某些邻域 f x ( x , y ) , f y ( x , y ) ) f_x(x,y),f_y(x,y)) fx(x,y),fy(x,y))中,然后将 将 f x ( x , y ) , f y ( x , y ) ) f_x(x,y),f_y(x,y)) fx(x,y),fy(x,y))的多项式作为插值像素值。 在OpenCV中,提供了几种插值方法。
OpenCV不支持CV_8S和CV_32S类型图像。
1、cv::resize
调整图像大小。
void cv::resize(InputArray src,OutputArray dst,Size dsize,double fx = 0,double fy = 0,int interpolation = INTER_LINEAR)
函数调整大小可将图像src调整为指定大小或最大。 请注意,未考虑初始dst类型或大小。 而是从src,dsize,fx和fy派生大小和类型。 如果要调整src的大小以使其适合预先创建的dst,则可以按以下方式调用该函数:
resize(src, dst, dst.size(), 0, 0, interpolation);
如果要在每个方向上将图像缩小2倍,则可以通过以下方式调用该函数:
resize(src, dst, Size(), 0.5, 0.5, interpolation);
要缩小图像,通常使用INTER_AREA插值效果最佳,而要放大图像,通常使用c :: INTER_CUBIC(速度慢)或INTER_LINEAR(速度更快,但看起来仍然可以)最好。
参数如下:
参数名称 | 参数描述 |
---|---|
src | 输入图像 |
dst | 输出图像;与dsize大小相同,(如果为非零)或根据src.size()或fx、fy计算得出的大小,dst与src类型相同 |
dsize | 输出图像大小; 如果为0,则dsize = Size(round(fxsrc.cols), round(fysrc.rows))否则 dsize 或fx 和fy必须为非零。 |
fx | 沿水平轴的比例因子; 当它等于0时,将计算为(double)dsize.width / src.cols |
fy | 沿垂直轴的比例因子; 当它等于0时,将计算为(double)dsize.height / src.rows |
interpolation | 插值方法, 请参考:InterpolationFlags |
2、cv::convertMaps、cv::remap
1)cv::convertMaps:将图像从一种映射转换为另一种映射。
void cv::convertMaps(InputArray map1,InputArray map2,OutputArray dstmap1,OutputArray dstmap2,int dstmap1type,bool nninterpolation = false)
该函数将一对映射从一个表示转换为另一种表示。 ( (map1.type(), map2.type()) → (dstmap1.type(), dstmap2.type()) )支持以下选项:
- KaTeX parse error: Expected '}', got '_' at position 12: \texttt{(CV_̲32FC1, CV_32FC1…这是最常用的转换操作,其中原始的浮点图(请参阅remap)被转换为更紧凑,更快的定点表示形式。 第一个输出数组包含舍入坐标,第二个数组(仅在nninterpolation = false时创建)包含插值表中的索引。
- KaTeX parse error: Expected '}', got '_' at position 12: \texttt{(CV_̲32FC2)} \righta…与上述相同,但原始地图存储在一个2通道矩阵中。
- 反向转换。 显然,重建的浮点图将与原始图不完全相同。
参数描述如下
参数名称 | 参数描述 |
---|---|
map1 | 类型为CV_16SC2,CV_32FC1或CV_32FC2的第一个输入映射。 |
map2 | 类型为CV_16SC2,CV_32FC1或CV_32FC2的第二个输入映射。 |
dstmap1 | 第一个输出映射的类型为dstmap1type,大小与src相同。 |
dstmap2 | 第一个输出映射的类型 |
dstmap1type | 第一个输出映射的类型应该为CV_16SC2,CV_32FC1或CV_32FC2。 |
nninterpolation | 指示定点图是用于最近邻居还是用于更复杂的插值的标志。 |
2)cv::remap:将通用的几何变换应用于图像。
void cv::remap(InputArray src,OutputArray dst,InputArray map1,InputArray map2,int interpolation,int borderMode = BORDER_CONSTANT,const Scalar & borderValue = Scalar())
函数remap使用指定的映射来转换源图像:
dst ( x , y ) = src ( m a p x ( x , y ) , m a p y ( x , y ) ) \texttt{dst} (x,y) = \texttt{src} (map_x(x,y),map_y(x,y)) dst(x,y)=src(mapx(x,y),mapy(x,y))
其中具有非整数坐标的像素值是使用一种可用的插值方法来计算的。 m a p x map_x mapx和 m a p y map_y mapy可以分别编码为map1和map2中的单独浮点图,也可以编码为map1中$(x,y)的交错浮点映射,或者使用convertMaps创建的定点映射。
该函数不能就地(in-place)转换
参数如下:
参数名称 | 参数描述 |
---|---|
src | 输入图像 |
dst | 目标图像。它的大小与map1相同,类型与src相同。 |
map1 | ( x , y ) (x,y) (x,y)点或仅x个值的第一个映射具有类型CV_16SC2,CV_32FC1或CV_32FC2。 |
map2 | 分别具有CV_16UC1,CV_32FC1或无类型的y值的第二个映射(如果map1是 ( x , y ) (x,y) (x,y)点,则为空映射)。 |
interpolation | 插值方法 (请参考InterpolationFlags).。 不支持INTER_AREA 插值类型 |
borderMode | 像素外推法(请参考BorderTypes)。当borderMode = BORDER_TRANSPARENT时,表示目标图像中的像素“对应于目标图像中的像素” 该功能未修改源图像。 |
borderValue | 边界不变时使用的值。 默认情况下为0。 |
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
/// 生成网格
/// \brief meshgrid
/// \param xgv 水平方向范围
/// \param ygv 垂直方向范围
/// \param X 输出水平方向网格
/// \param Y 输出垂直方向网格
///
void meshgrid(const cv::Range &xgv, const cv::Range &ygv, cv::Mat &X, cv::Mat &Y)
{
std::vector<int> t_x, t_y;
for(int i = xgv.start; i <= xgv.end; i++) t_x.push_back(i);
for(int j = ygv.start; j <= ygv.end; j++) t_y.push_back(j);
cv::repeat(cv::Mat(t_x).t(), t_y.size(), 1, X);
cv::repeat(cv::Mat(t_y), 1, t_x.size(), Y);
}
/// 计算形变网格
/// \brief deformation_to_transformation
/// \param ux 水平方向范围
/// \param uy 垂直方向范围
/// \param dx 水平方向形变量
/// \param dy 垂直方向形变量
/// \param xgv 水平方向范围
/// \param ygv 垂直方向范围
///
void deformation_to_transformation(cv::Mat& ux,cv::Mat &uy,int dx,int dy,
const cv::Range &xgv, const cv::Range &ygv){
meshgrid(xgv,ygv,ux,uy);
ux.convertTo(ux,CV_32FC1);
ux += dx;
uy.convertTo(uy,CV_32FC1);
uy += dy;
}
/// 平移图像
/// \brief dense_image_warp
/// \param src 输入图像
/// \param dst 输出图像
/// \param dx 水平方向平移量
/// \param dy 垂直方向平移量
///
void dense_image_warp(const cv::Mat& src,cv::Mat& dst,int dx,int dy){
int rows = src.rows;
int cols = src.cols;
cv::Mat map_x,map_y,ux,uy;
deformation_to_transformation(ux,uy,dx,dy,cv::Range(0,cols),cv::Range(0,rows));
// 计算映射坐标
cv::convertMaps(ux,uy,map_x,map_y,CV_16SC2);
// 坐标生重映射,重建图像
cv::remap(src,dst,map_x,map_y,cv::INTER_NEAREST);
}
int main()
{
// 读取图像
cv::Mat src = cv::imread("images/f1.jpg");
cv::Mat dst;
// 计算平移输出图像
dense_image_warp(src,dst,-50,50);
// 显示图像
cv::imshow("src",src);
cv::imshow("dst",dst);
cv::waitKey();
cv::destroyAllWindows();
return 0;
}
3、cv::warpAffine、cv::invertAffineTransform、cv::getAffineTransform、cv::getRotationMatrix2D、cv::getRotationMatrix2D_
1)cv::warpAffine:对图像应用仿射变换。
void cv::warpAffine(InputArray src,OutputArray dst,InputArray M,Size dsize,int flags = INTER_LINEAR,int borderMode = BORDER_CONSTANT,const Scalar & borderValue = Scalar())
函数warpAffine使用指定的矩阵转换源图像:
dst ( x , y ) = src ( M 11 x + M 12 y + M 13 , M 21 x + M 22 y + M 23 ) \texttt{dst} (x,y) = \texttt{src} ( \texttt{M} _{11} x + \texttt{M} _{12} y + \texttt{M} _{13}, \texttt{M} _{21} x + \texttt{M} _{22} y + \texttt{M} _{23}) dst(x,y)=src(M11x+M12y+M13,M21x+M22y+M23)
当设置标志WARP_INVERSE_MAP时。 否则,首先使用invertAffineTransform反转转换,然后将其放在上面的公式中,而不是M。该函数无法就地操作。
参数如下:
参数名称 | 参数描述 |
---|---|
src | 输入图像 |
dst | 输出图像,输出图像,其大小为dsize,并且类型与src相同。 |
M | 2×3转换矩阵 |
dsize | 输出图像大小 |
flags | 插值方法的组合 (参考InterpolationFlags) 当flag为 WARP_INVERSE_MAP 时, M 是反向转换 ( dst→src ). |
borderMode | 像素外推法 (参考BorderTypes);当 borderMode=BORDER_TRANSPARENT,时,这意味着目标图像中与源图像中的“离群值”相对应的像素不会被该功能修改。 |
borderValue | 在边界不变的情况下使用的值; 默认情况下为0。 |
2)cv::invertAffineTransform:反转仿射变换。
void cv::invertAffineTransform(InputArray M,OutputArray iM)
该函数计算由2×3矩阵M表示的逆仿射变换:
[ a 11 a 12 b 1 a 21 a 22 b 2 ] \begin{bmatrix} a_{11} & a_{12} & b_1 \\ a_{21} & a_{22} & b_2 \end{bmatrix} [a11a21a12a22b1b2]
结果与M相同类型的 2 × 3 2×3 2×3矩阵。
参数如下:
参数名称 | 参数描述 |
---|---|
M | 原始仿射变换。 |
iM | 输出反向仿射变换。 |
3)cv::getAffineTransform:根据三对对应点计算仿射变换。
- Mat cv::getAffineTransform(const Point2f src[],const Point2f dst[])
- Mat cv::getAffineTransform(InputArray src,InputArray dst)
该函数计算仿射变换的2×3矩阵,如下:
KaTeX parse error: Expected '}', got '_' at position 57: …} = \texttt{map_̲matrix} \cdot \…
其中,
d
s
t
(
i
)
=
(
x
i
′
,
y
i
′
)
,
s
r
c
(
i
)
=
(
x
i
,
y
i
)
,
i
=
0
,
1
,
2
dst(i)=(x'_i,y'_i), src(i)=(x_i, y_i), i=0,1,2
dst(i)=(xi′,yi′),src(i)=(xi,yi),i=0,1,2
参数如下:
参数名称 | 参数描述 |
---|---|
src | 源图像中三角形顶点的坐标。 |
dst | 目标图像中相应三角形顶点的坐标。 |
示例如下:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
int main()
{
// 读取图像
cv::Mat src = cv::imread("images/f1.jpg");
if(src.empty()){
cerr << "cannot read image.\n";
return EXIT_FAILURE;
}
cv::Mat dst;
int rows = src.rows;
int cols = src.cols;
//源图像和目标图像对应映射的三点
cv::Point2f srcPoint[3];
cv::Point2f resPoint[3];
srcPoint[0] = cv::Point2f(0, 0);
srcPoint[1] = cv::Point2f(cols - 1, 0);
srcPoint[2] = cv::Point2f(0, rows - 1);
resPoint[0] = cv::Point2f(cols * 0, rows*0.33);
resPoint[1] = cv::Point2f(cols*0.85, rows*0.25);
resPoint[2] = cv::Point2f(cols*0.15, rows*0.7);
// 定义仿射变换矩阵2X3
cv::Mat warpMat(cv::Size(2, 3), CV_32F);
dst = cv::Mat::zeros(rows, cols, src.type());
// 计算仿射变换矩阵,即仿射变换的2*3数组
warpMat = cv::getAffineTransform(srcPoint, resPoint);
// 根据仿射矩阵计算图像仿射变换
cv::warpAffine(src, dst,
warpMat, dst.size());
cv::imshow("dst", dst);
cv::imshow("src",src);
cv::waitKey();
cv::destroyAllWindows();
return 0;
}
3)cv::getRotationMatrix2D:计算2D旋转的仿射矩阵。
该函数计算以下矩阵:
[ α β ( 1 − α ) ⋅ center.x − β ⋅ center.y − β α β ⋅ center.x + ( 1 − α ) ⋅ center.y ] \begin{bmatrix} \alpha & \beta & (1- \alpha ) \cdot \texttt{center.x} - \beta \cdot \texttt{center.y} \\ - \beta & \alpha & \beta \cdot \texttt{center.x} + (1- \alpha ) \cdot \texttt{center.y} \end{bmatrix} [α−ββα(1−α)⋅center.x−β⋅center.yβ⋅center.x+(1−α)⋅center.y]
其中, α = scale ⋅ cos angle , β = scale ⋅ sin angle \begin{array}{l} \alpha = \texttt{scale} \cdot \cos \texttt{angle} , \\ \beta = \texttt{scale} \cdot \sin \texttt{angle} \end{array} α=scale⋅cosangle,β=scale⋅sinangle
变换将旋转中心映射到其自身。如果不是目标,调整转变。
参数如下:
参数名称 | 参数描述 |
---|---|
center | 输入图像旋转中心 |
angle | 旋转角度(度)。 正值表示逆时针旋转(假设坐标原点为左上角)。 |
scale | 各向同性比例因子。 |
cv::Point2f centerPoint = cv::Point2f(cols / 2, rows / 2);
double angle = -50;
double scale = 0.7;
// 获取旋转仿射变换矩阵
warpMat = getRotationMatrix2D(centerPoint, angle, scale);
// 根据仿射矩阵计算图像仿射变换
cv::warpAffine(src, dst,warpMat, dst.size());
4、cv::warpPerspective、cv::getPerspectiveTransform
1)cv::warpPerspective:将透视变换应用于图像。
void cv::warpPerspective(InputArray src,OutputArray dst,InputArray M,Size dsize,int flags = INTER_LINEAR,int borderMode = BORDER_CONSTANT,const Scalar & borderValue = Scalar())
函数warpPerspective使用指定的矩阵转换源图像:
dst ( x , y ) = src ( M 11 x + M 12 y + M 13 M 31 x + M 32 y + M 33 , M 21 x + M 22 y + M 23 M 31 x + M 32 y + M 33 ) \texttt{dst} (x,y) = \texttt{src} \left ( \frac{M_{11} x + M_{12} y + M_{13}}{M_{31} x + M_{32} y + M_{33}} , \frac{M_{21} x + M_{22} y + M_{23}}{M_{31} x + M_{32} y + M_{33}} \right ) dst(x,y)=src(M31x+M32y+M33M11x+M12y+M13,M31x+M32y+M33M21x+M22y+M23)
当设置标志WARP_INVERSE_MAP时。 否则,首先使用invert反转转换,然后将其放在上面的公式中,而不是M。函数无法就地操作。
Parameters
参数名称 | 参数描述 |
---|---|
src | 输入图像 |
dst | 输出图像,其大小为dsize,并且类型与src相同。 |
M | 3×3 转换矩阵 |
dsize | 输出图像大小 |
flags | 插值方法(INTER_LINEAR或INTER_NEAREST)与可选标志WARP_INVERSE_MAP的组合,将M设置为逆变换(dst→src)。 |
borderMode | 像素外推法 (BORDER_CONSTANT or BORDER_REPLICATE). |
borderValue | 在边界不变的情况下使用的值; 默认情况下为0。 |
2)cv::getPerspectiveTransform:根据四对对应点计算透视变换。
该函数计算透视变换的3×3矩阵,如下:
KaTeX parse error: Expected '}', got '_' at position 72: …} = \texttt{map_̲matrix} \cdot \…
其中: d s t ( i ) = ( x i ′ , y i ′ ) , s r c ( i ) = ( x i , y i ) , i = 0 , 1 , 2 , 3 dst(i)=(x'_i,y'_i), src(i)=(x_i, y_i), i=0,1,2,3 dst(i)=(xi′,yi′),src(i)=(xi,yi),i=0,1,2,3
参数如下:
参数名称 | 参数描述 |
---|---|
src | 源图像中四边形顶点的坐标。 |
dst | 目标图像中相应四边形顶点的坐标。 |
solveMethod | 求解方法,传递给 cv::solve (DecompTypes) |
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
int main()
{
// 读取图像
cv::Mat src = cv::imread("images/f1.jpg");
if(src.empty()){
cerr << "cannot read image.\n";
return EXIT_FAILURE;
}
cv::Mat dst;
cv::Point2f src_points[] = {
cv::Point2f(165, 640),
cv::Point2f(835, 640),
cv::Point2f(360, 125),
cv::Point2f(615, 125) };
cv::Point2f dst_points[] = {
cv::Point2f(165, 640),
cv::Point2f(835, 640),
cv::Point2f(165, 30),
cv::Point2f(835, 30) };
cv::Mat M = cv::getPerspectiveTransform(src_points, dst_points);
cv::warpPerspective(src, dst, M, cv::Size(960, 640), cv::INTER_LINEAR);
cv::imshow("src",src);
cv::imshow("dst",dst);
cv::waitKey();
cv::destroyAllWindows();
return 0;
}
5、cv::linearPolar、cv::logPolar、cv::warpPolar
1)cv::linearPolar:将图像重新映射到极坐标空间。
void cv::linearPolar(InputArray src,OutputArray dst,Point2f center,double maxRadius,int flags)
注意,这个函数已经过时,与函数**cv::warpPolar(src, dst, src.size(), center, maxRadius, flags)**调用的结果相同。
#include <iostream>
#include <opencv2/opencv.hpp>
#include <cmath>
using namespace std;
int main()
{
// 读取图像
cv::Mat src = cv::imread("images/f1.jpg");
if(src.empty()){
cerr << "cannot read image.\n";
return EXIT_FAILURE;
}
cv::Mat dst;
// 计算最半径
cv::Point2f center( (float)src.cols / 2, (float)src.rows / 2 );
double maxRadius = 0.7*min(center.y, center.x);
int flags = cv::INTER_LINEAR + cv::WARP_FILL_OUTLIERS;
cv::linearPolar(src,dst,center,maxRadius,flags);
// 显示图像
cv::imshow("src",src);
cv::imshow("dst",dst);
cv::waitKey();
cv::destroyAllWindows();
return 0;
}
2)cv::logPolar:将图像重新映射到半对数极坐标空间。
void cv::logPolar(InputArray src,OutputArray dst,Point2f center,double M,int flags)
注意,这个函数已经过时,与函数**cv::warpPolar(src, dst, src.size(), center, maxRadius, flags+WARP_POLAR_LOG)**调用的结果相同。
#include <iostream>
#include <opencv2/opencv.hpp>
#include <cmath>
using namespace std;
int main()
{
// 读取图像
cv::Mat src = cv::imread("images/f1.jpg");
if(src.empty()){
cerr << "cannot read image.\n";
return EXIT_FAILURE;
}
cv::Mat dst;
// 计算最半径
cv::Point2f center( (float)src.cols / 2, (float)src.rows / 2 );
double maxRadius = 0.7*min(center.y, center.x);
int flags = cv::INTER_LINEAR + cv::WARP_FILL_OUTLIERS;
cv::logPolar(src,dst,center,maxRadius,flags);
// 显示图像
cv::imshow("src",src);
cv::imshow("dst",dst);
cv::waitKey();
cv::destroyAllWindows();
return 0;
}
3)cv::warpPolar:将图像重新映射到极坐标或半对数坐标空间。
void cv::warpPolar(InputArray src,OutputArray dst,Size dsize,Point2f center,double maxRadius,int flags)
wrapPolar函数通过如下函数进行转换:
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之一添加到标志以指定极坐标映射模式。线性是默认模式。
半对数映射模拟了人类的“中心凹”视觉,与视力较弱的周围视觉相反,该视线允许很高的视线(中央视力)。
输出图像大小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。
参数说明如下:
参数名称 | 参数描述 |
---|---|
src | 输入图像 |
dst | 输出图像,与src大小相同 。 |
dsize | 指定输出图像大小,见前面描述 |
center | 变换中心位置 |
maxRadius | 要变换的边界圆的半径。 它也确定反幅度标度参数。 |
flags | 插值方法的组合, InterpolationFlags + WarpPolarMode、 WARP_POLAR_LINEAR 为线性;加WARP_POLAR_LOG为半对数;加WARP_INVERSE_MAP 为反向变换。 |
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
int main()
{
// 读取图像
cv::Mat src = cv::imread("images/f1.jpg");
if(src.empty()){
cerr << "cannot read image.\n";
return EXIT_FAILURE;
}
cv::Mat dst1,dst2,dst3;
cv::Point2f center( (float)src.cols / 2, (float)src.rows / 2 );
double maxRadius = min(center.y, center.x);
cv::warpPolar(src, dst1, src.size(),
center,maxRadius,cv::INTER_LINEAR + cv::WARP_POLAR_LINEAR);
cv::warpPolar(dst1, dst2, src.size(),
center,maxRadius,cv::INTER_LINEAR+cv::WARP_INVERSE_MAP);
cv::warpPolar(src, dst3, src.size(),
center,maxRadius,cv::INTER_LINEAR+cv::WARP_POLAR_LOG);
cv::imshow("src",src);
cv::imshow("linear",dst1);
cv::imshow("linear-invert",dst2);
cv::imshow("log",dst3);
cv::waitKey();
cv::destroyAllWindows();
return 0;
}
注意:
- 该函数无法就地操作。
- 为了计算度数和角度(以度为单位),内部使用cartToPolar,因此可以从0到360度测量角度,精度约为0.3度。
- 此函数使用重映射。 由于当前的实现限制,输入和输出图像的大小应小于32767x32767。
另外,如果需要从极坐标映射到计算原始坐标映射,可以按如下操作:
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));